XmlStreamNodeWriter.cs 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794
  1. //------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //------------------------------------------------------------
  4. namespace System.Xml
  5. {
  6. using System.IO;
  7. using System.Runtime;
  8. using System.Runtime.Serialization;
  9. using System.Security;
  10. using System.Text;
  11. using System.Threading;
  12. abstract class XmlStreamNodeWriter : XmlNodeWriter
  13. {
  14. Stream stream;
  15. byte[] buffer;
  16. int offset;
  17. bool ownsStream;
  18. const int bufferLength = 512;
  19. const int maxEntityLength = 32;
  20. const int maxBytesPerChar = 3;
  21. Encoding encoding;
  22. int hasPendingWrite;
  23. AsyncEventArgs<object> flushBufferState;
  24. static UTF8Encoding UTF8Encoding = new UTF8Encoding(false, true);
  25. static AsyncCallback onFlushBufferComplete;
  26. static AsyncEventArgsCallback onGetFlushComplete;
  27. protected XmlStreamNodeWriter()
  28. {
  29. this.buffer = new byte[bufferLength];
  30. encoding = XmlStreamNodeWriter.UTF8Encoding;
  31. }
  32. protected void SetOutput(Stream stream, bool ownsStream, Encoding encoding)
  33. {
  34. this.stream = stream;
  35. this.ownsStream = ownsStream;
  36. this.offset = 0;
  37. if (encoding != null)
  38. {
  39. this.encoding = encoding;
  40. }
  41. }
  42. // Getting/Setting the Stream exists for fragmenting
  43. public Stream Stream
  44. {
  45. get
  46. {
  47. return stream;
  48. }
  49. set
  50. {
  51. stream = value;
  52. }
  53. }
  54. // StreamBuffer/BufferOffset exists only for the BinaryWriter to fix up nodes
  55. public byte[] StreamBuffer
  56. {
  57. get
  58. {
  59. return buffer;
  60. }
  61. }
  62. public int BufferOffset
  63. {
  64. get
  65. {
  66. return offset;
  67. }
  68. }
  69. public int Position
  70. {
  71. get
  72. {
  73. return (int)stream.Position + offset;
  74. }
  75. }
  76. protected byte[] GetBuffer(int count, out int offset)
  77. {
  78. Fx.Assert(count >= 0 && count <= bufferLength, "");
  79. int bufferOffset = this.offset;
  80. if (bufferOffset + count <= bufferLength)
  81. {
  82. offset = bufferOffset;
  83. }
  84. else
  85. {
  86. FlushBuffer();
  87. offset = 0;
  88. }
  89. #if DEBUG
  90. Fx.Assert(offset + count <= bufferLength, "");
  91. for (int i = 0; i < count; i++)
  92. {
  93. buffer[offset + i] = (byte)'<';
  94. }
  95. #endif
  96. return buffer;
  97. }
  98. internal AsyncCompletionResult GetBufferAsync(GetBufferAsyncEventArgs getBufferState)
  99. {
  100. Fx.Assert(getBufferState != null, "GetBufferAsyncEventArgs cannot be null.");
  101. int count = getBufferState.Arguments.Count;
  102. Fx.Assert(count >= 0 && count <= bufferLength, String.Empty);
  103. int finalOffset = 0;
  104. int bufferOffset = this.offset;
  105. if (bufferOffset + count <= bufferLength)
  106. {
  107. finalOffset = bufferOffset;
  108. }
  109. else
  110. {
  111. if (onGetFlushComplete == null)
  112. {
  113. onGetFlushComplete = new AsyncEventArgsCallback(GetBufferFlushComplete);
  114. }
  115. if (flushBufferState == null)
  116. {
  117. this.flushBufferState = new AsyncEventArgs<object>();
  118. }
  119. this.flushBufferState.Set(onGetFlushComplete, getBufferState, this);
  120. if (FlushBufferAsync(this.flushBufferState) == AsyncCompletionResult.Completed)
  121. {
  122. finalOffset = 0;
  123. this.flushBufferState.Complete(true);
  124. }
  125. else
  126. {
  127. return AsyncCompletionResult.Queued;
  128. }
  129. }
  130. #if DEBUG
  131. Fx.Assert(finalOffset + count <= bufferLength, "");
  132. for (int i = 0; i < count; i++)
  133. {
  134. buffer[finalOffset + i] = (byte)'<';
  135. }
  136. #endif
  137. //return the buffer and finalOffset;
  138. getBufferState.Result = getBufferState.Result ?? new GetBufferEventResult();
  139. getBufferState.Result.Buffer = this.buffer;
  140. getBufferState.Result.Offset = finalOffset;
  141. return AsyncCompletionResult.Completed;
  142. }
  143. static void GetBufferFlushComplete(IAsyncEventArgs completionState)
  144. {
  145. XmlStreamNodeWriter thisPtr = (XmlStreamNodeWriter)completionState.AsyncState;
  146. GetBufferAsyncEventArgs getBufferState = (GetBufferAsyncEventArgs)thisPtr.flushBufferState.Arguments;
  147. getBufferState.Result = getBufferState.Result ?? new GetBufferEventResult();
  148. getBufferState.Result.Buffer = thisPtr.buffer;
  149. getBufferState.Result.Offset = 0;
  150. getBufferState.Complete(false, completionState.Exception);
  151. }
  152. AsyncCompletionResult FlushBufferAsync(AsyncEventArgs<object> state)
  153. {
  154. if (Interlocked.CompareExchange(ref this.hasPendingWrite, 1, 0) != 0)
  155. {
  156. throw FxTrace.Exception.AsError(new InvalidOperationException(SR.GetString(SR.FlushBufferAlreadyInUse)));
  157. }
  158. if (this.offset != 0)
  159. {
  160. if (onFlushBufferComplete == null)
  161. {
  162. onFlushBufferComplete = new AsyncCallback(OnFlushBufferCompete);
  163. }
  164. IAsyncResult result = stream.BeginWrite(buffer, 0, this.offset, onFlushBufferComplete, this);
  165. if (!result.CompletedSynchronously)
  166. {
  167. return AsyncCompletionResult.Queued;
  168. }
  169. stream.EndWrite(result);
  170. this.offset = 0;
  171. }
  172. if (Interlocked.CompareExchange(ref this.hasPendingWrite, 0, 1) != 1)
  173. {
  174. throw FxTrace.Exception.AsError(new InvalidOperationException(SR.GetString(SR.NoAsyncWritePending)));
  175. }
  176. return AsyncCompletionResult.Completed;
  177. }
  178. static void OnFlushBufferCompete(IAsyncResult result)
  179. {
  180. if (result.CompletedSynchronously)
  181. {
  182. return;
  183. }
  184. XmlStreamNodeWriter thisPtr = (XmlStreamNodeWriter)result.AsyncState;
  185. Exception completionException = null;
  186. try
  187. {
  188. thisPtr.stream.EndWrite(result);
  189. thisPtr.offset = 0;
  190. if (Interlocked.CompareExchange(ref thisPtr.hasPendingWrite, 0, 1) != 1)
  191. {
  192. throw FxTrace.Exception.AsError(new InvalidOperationException(SR.GetString(SR.NoAsyncWritePending)));
  193. }
  194. }
  195. catch (Exception ex)
  196. {
  197. if (Fx.IsFatal(ex))
  198. {
  199. throw;
  200. }
  201. completionException = ex;
  202. }
  203. thisPtr.flushBufferState.Complete(false, completionException);
  204. }
  205. protected IAsyncResult BeginGetBuffer(int count, AsyncCallback callback, object state)
  206. {
  207. Fx.Assert(count >= 0 && count <= bufferLength, "");
  208. return new GetBufferAsyncResult(count, this, callback, state);
  209. }
  210. protected byte[] EndGetBuffer(IAsyncResult result, out int offset)
  211. {
  212. return GetBufferAsyncResult.End(result, out offset);
  213. }
  214. class GetBufferAsyncResult : AsyncResult
  215. {
  216. XmlStreamNodeWriter writer;
  217. int offset;
  218. int count;
  219. static AsyncCompletion onComplete = new AsyncCompletion(OnComplete);
  220. public GetBufferAsyncResult(int count, XmlStreamNodeWriter writer, AsyncCallback callback, object state)
  221. : base(callback, state)
  222. {
  223. this.count = count;
  224. this.writer = writer;
  225. int bufferOffset = writer.offset;
  226. bool completeSelf = false;
  227. if (bufferOffset + count <= bufferLength)
  228. {
  229. this.offset = bufferOffset;
  230. completeSelf = true;
  231. }
  232. else
  233. {
  234. IAsyncResult result = writer.BeginFlushBuffer(PrepareAsyncCompletion(onComplete), this);
  235. completeSelf = SyncContinue(result);
  236. }
  237. if (completeSelf)
  238. {
  239. this.Complete(true);
  240. }
  241. }
  242. static bool OnComplete(IAsyncResult result)
  243. {
  244. GetBufferAsyncResult thisPtr = (GetBufferAsyncResult)result.AsyncState;
  245. return thisPtr.HandleFlushBuffer(result);
  246. }
  247. bool HandleFlushBuffer(IAsyncResult result)
  248. {
  249. writer.EndFlushBuffer(result);
  250. this.offset = 0;
  251. #if DEBUG
  252. Fx.Assert(this.offset + this.count <= bufferLength, "");
  253. for (int i = 0; i < this.count; i++)
  254. {
  255. writer.buffer[this.offset + i] = (byte)'<';
  256. }
  257. #endif
  258. return true;
  259. }
  260. public static byte[] End(IAsyncResult result, out int offset)
  261. {
  262. GetBufferAsyncResult thisPtr = AsyncResult.End<GetBufferAsyncResult>(result);
  263. offset = thisPtr.offset;
  264. return thisPtr.writer.buffer;
  265. }
  266. }
  267. protected void Advance(int count)
  268. {
  269. Fx.Assert(offset + count <= bufferLength, "");
  270. offset += count;
  271. }
  272. void EnsureByte()
  273. {
  274. if (offset >= bufferLength)
  275. {
  276. FlushBuffer();
  277. }
  278. }
  279. protected void WriteByte(byte b)
  280. {
  281. EnsureByte();
  282. buffer[offset++] = b;
  283. }
  284. protected void WriteByte(char ch)
  285. {
  286. Fx.Assert(ch < 0x80, "");
  287. WriteByte((byte)ch);
  288. }
  289. protected void WriteBytes(byte b1, byte b2)
  290. {
  291. byte[] buffer = this.buffer;
  292. int offset = this.offset;
  293. if (offset + 1 >= bufferLength)
  294. {
  295. FlushBuffer();
  296. offset = 0;
  297. }
  298. buffer[offset + 0] = b1;
  299. buffer[offset + 1] = b2;
  300. this.offset += 2;
  301. }
  302. protected void WriteBytes(char ch1, char ch2)
  303. {
  304. Fx.Assert(ch1 < 0x80 && ch2 < 0x80, "");
  305. WriteBytes((byte)ch1, (byte)ch2);
  306. }
  307. public void WriteBytes(byte[] byteBuffer, int byteOffset, int byteCount)
  308. {
  309. if (byteCount < bufferLength)
  310. {
  311. int offset;
  312. byte[] buffer = GetBuffer(byteCount, out offset);
  313. Buffer.BlockCopy(byteBuffer, byteOffset, buffer, offset, byteCount);
  314. Advance(byteCount);
  315. }
  316. else
  317. {
  318. FlushBuffer();
  319. stream.Write(byteBuffer, byteOffset, byteCount);
  320. }
  321. }
  322. public IAsyncResult BeginWriteBytes(byte[] byteBuffer, int byteOffset, int byteCount, AsyncCallback callback, object state)
  323. {
  324. return new WriteBytesAsyncResult(byteBuffer, byteOffset, byteCount, this, callback, state);
  325. }
  326. public void EndWriteBytes(IAsyncResult result)
  327. {
  328. WriteBytesAsyncResult.End(result);
  329. }
  330. class WriteBytesAsyncResult : AsyncResult
  331. {
  332. static AsyncCompletion onHandleGetBufferComplete = new AsyncCompletion(OnHandleGetBufferComplete);
  333. static AsyncCompletion onHandleFlushBufferComplete = new AsyncCompletion(OnHandleFlushBufferComplete);
  334. static AsyncCompletion onHandleWrite = new AsyncCompletion(OnHandleWrite);
  335. byte[] byteBuffer;
  336. int byteOffset;
  337. int byteCount;
  338. XmlStreamNodeWriter writer;
  339. public WriteBytesAsyncResult(byte[] byteBuffer, int byteOffset, int byteCount, XmlStreamNodeWriter writer, AsyncCallback callback, object state)
  340. : base(callback, state)
  341. {
  342. this.byteBuffer = byteBuffer;
  343. this.byteOffset = byteOffset;
  344. this.byteCount = byteCount;
  345. this.writer = writer;
  346. bool completeSelf = false;
  347. if (byteCount < bufferLength)
  348. {
  349. completeSelf = HandleGetBuffer(null);
  350. }
  351. else
  352. {
  353. completeSelf = HandleFlushBuffer(null);
  354. }
  355. if (completeSelf)
  356. {
  357. this.Complete(true);
  358. }
  359. }
  360. static bool OnHandleGetBufferComplete(IAsyncResult result)
  361. {
  362. WriteBytesAsyncResult thisPtr = (WriteBytesAsyncResult)result.AsyncState;
  363. return thisPtr.HandleGetBuffer(result);
  364. }
  365. static bool OnHandleFlushBufferComplete(IAsyncResult result)
  366. {
  367. WriteBytesAsyncResult thisPtr = (WriteBytesAsyncResult)result.AsyncState;
  368. return thisPtr.HandleFlushBuffer(result);
  369. }
  370. static bool OnHandleWrite(IAsyncResult result)
  371. {
  372. WriteBytesAsyncResult thisPtr = (WriteBytesAsyncResult)result.AsyncState;
  373. return thisPtr.HandleWrite(result);
  374. }
  375. bool HandleGetBuffer(IAsyncResult result)
  376. {
  377. if (result == null)
  378. {
  379. result = writer.BeginGetBuffer(this.byteCount, PrepareAsyncCompletion(onHandleGetBufferComplete), this);
  380. if (!result.CompletedSynchronously)
  381. {
  382. return false;
  383. }
  384. }
  385. int offset;
  386. byte[] buffer = writer.EndGetBuffer(result, out offset);
  387. Buffer.BlockCopy(this.byteBuffer, this.byteOffset, buffer, offset, this.byteCount);
  388. writer.Advance(this.byteCount);
  389. return true;
  390. }
  391. bool HandleFlushBuffer(IAsyncResult result)
  392. {
  393. if (result == null)
  394. {
  395. result = writer.BeginFlushBuffer(PrepareAsyncCompletion(onHandleFlushBufferComplete), this);
  396. if (!result.CompletedSynchronously)
  397. {
  398. return false;
  399. }
  400. }
  401. writer.EndFlushBuffer(result);
  402. return HandleWrite(null);
  403. }
  404. bool HandleWrite(IAsyncResult result)
  405. {
  406. if (result == null)
  407. {
  408. result = writer.stream.BeginWrite(this.byteBuffer, this.byteOffset, this.byteCount, PrepareAsyncCompletion(onHandleWrite), this);
  409. if (!result.CompletedSynchronously)
  410. {
  411. return false;
  412. }
  413. }
  414. writer.stream.EndWrite(result);
  415. return true;
  416. }
  417. public static void End(IAsyncResult result)
  418. {
  419. AsyncResult.End<WriteBytesAsyncResult>(result);
  420. }
  421. }
  422. [Fx.Tag.SecurityNote(Critical = "Contains unsafe code. Caller needs to validate arguments.")]
  423. [SecurityCritical]
  424. unsafe protected void UnsafeWriteBytes(byte* bytes, int byteCount)
  425. {
  426. FlushBuffer();
  427. byte[] buffer = this.buffer;
  428. while (byteCount > bufferLength)
  429. {
  430. for (int i = 0; i < bufferLength; i++)
  431. buffer[i] = bytes[i];
  432. stream.Write(buffer, 0, bufferLength);
  433. bytes += bufferLength;
  434. byteCount -= bufferLength;
  435. }
  436. if (byteCount > 0)
  437. {
  438. for (int i = 0; i < byteCount; i++)
  439. buffer[i] = bytes[i];
  440. stream.Write(buffer, 0, byteCount);
  441. }
  442. }
  443. [Fx.Tag.SecurityNote(Critical = "Contains unsafe code.",
  444. Safe = "Unsafe code is effectively encapsulated, all inputs are validated.")]
  445. [SecuritySafeCritical]
  446. unsafe protected void WriteUTF8Char(int ch)
  447. {
  448. if (ch < 0x80)
  449. {
  450. WriteByte((byte)ch);
  451. }
  452. else if (ch <= char.MaxValue)
  453. {
  454. char* chars = stackalloc char[1];
  455. chars[0] = (char)ch;
  456. UnsafeWriteUTF8Chars(chars, 1);
  457. }
  458. else
  459. {
  460. SurrogateChar surrogateChar = new SurrogateChar(ch);
  461. char* chars = stackalloc char[2];
  462. chars[0] = surrogateChar.HighChar;
  463. chars[1] = surrogateChar.LowChar;
  464. UnsafeWriteUTF8Chars(chars, 2);
  465. }
  466. }
  467. protected void WriteUTF8Chars(byte[] chars, int charOffset, int charCount)
  468. {
  469. if (charCount < bufferLength)
  470. {
  471. int offset;
  472. byte[] buffer = GetBuffer(charCount, out offset);
  473. Buffer.BlockCopy(chars, charOffset, buffer, offset, charCount);
  474. Advance(charCount);
  475. }
  476. else
  477. {
  478. FlushBuffer();
  479. stream.Write(chars, charOffset, charCount);
  480. }
  481. }
  482. [Fx.Tag.SecurityNote(Critical = "Contains unsafe code.",
  483. Safe = "Unsafe code is effectively encapsulated, all inputs are validated.")]
  484. [SecuritySafeCritical]
  485. unsafe protected void WriteUTF8Chars(string value)
  486. {
  487. int count = value.Length;
  488. if (count > 0)
  489. {
  490. fixed (char* chars = value)
  491. {
  492. UnsafeWriteUTF8Chars(chars, count);
  493. }
  494. }
  495. }
  496. [Fx.Tag.SecurityNote(Critical = "Contains unsafe code. Caller needs to validate arguments.")]
  497. [SecurityCritical]
  498. unsafe protected void UnsafeWriteUTF8Chars(char* chars, int charCount)
  499. {
  500. const int charChunkSize = bufferLength / maxBytesPerChar;
  501. while (charCount > charChunkSize)
  502. {
  503. int offset;
  504. int chunkSize = charChunkSize;
  505. if ((int)(chars[chunkSize - 1] & 0xFC00) == 0xD800) // This is a high surrogate
  506. chunkSize--;
  507. byte[] buffer = GetBuffer(chunkSize * maxBytesPerChar, out offset);
  508. Advance(UnsafeGetUTF8Chars(chars, chunkSize, buffer, offset));
  509. charCount -= chunkSize;
  510. chars += chunkSize;
  511. }
  512. if (charCount > 0)
  513. {
  514. int offset;
  515. byte[] buffer = GetBuffer(charCount * maxBytesPerChar, out offset);
  516. Advance(UnsafeGetUTF8Chars(chars, charCount, buffer, offset));
  517. }
  518. }
  519. [Fx.Tag.SecurityNote(Critical = "Contains unsafe code. Caller needs to validate arguments.")]
  520. [SecurityCritical]
  521. unsafe protected void UnsafeWriteUnicodeChars(char* chars, int charCount)
  522. {
  523. const int charChunkSize = bufferLength / 2;
  524. while (charCount > charChunkSize)
  525. {
  526. int offset;
  527. int chunkSize = charChunkSize;
  528. if ((int)(chars[chunkSize - 1] & 0xFC00) == 0xD800) // This is a high surrogate
  529. chunkSize--;
  530. byte[] buffer = GetBuffer(chunkSize * 2, out offset);
  531. Advance(UnsafeGetUnicodeChars(chars, chunkSize, buffer, offset));
  532. charCount -= chunkSize;
  533. chars += chunkSize;
  534. }
  535. if (charCount > 0)
  536. {
  537. int offset;
  538. byte[] buffer = GetBuffer(charCount * 2, out offset);
  539. Advance(UnsafeGetUnicodeChars(chars, charCount, buffer, offset));
  540. }
  541. }
  542. [Fx.Tag.SecurityNote(Critical = "Contains unsafe code. Caller needs to validate arguments.")]
  543. [SecurityCritical]
  544. unsafe protected int UnsafeGetUnicodeChars(char* chars, int charCount, byte[] buffer, int offset)
  545. {
  546. char* charsMax = chars + charCount;
  547. while (chars < charsMax)
  548. {
  549. char value = *chars++;
  550. buffer[offset++] = (byte)value;
  551. value >>= 8;
  552. buffer[offset++] = (byte)value;
  553. }
  554. return charCount * 2;
  555. }
  556. [Fx.Tag.SecurityNote(Critical = "Contains unsafe code. Caller needs to validate arguments.")]
  557. [SecurityCritical]
  558. unsafe protected int UnsafeGetUTF8Length(char* chars, int charCount)
  559. {
  560. char* charsMax = chars + charCount;
  561. while (chars < charsMax)
  562. {
  563. if (*chars >= 0x80)
  564. break;
  565. chars++;
  566. }
  567. if (chars == charsMax)
  568. return charCount;
  569. return (int)(chars - (charsMax - charCount)) + encoding.GetByteCount(chars, (int)(charsMax - chars));
  570. }
  571. [Fx.Tag.SecurityNote(Critical = "Contains unsafe code. Caller needs to validate arguments.")]
  572. [SecurityCritical]
  573. unsafe protected int UnsafeGetUTF8Chars(char* chars, int charCount, byte[] buffer, int offset)
  574. {
  575. if (charCount > 0)
  576. {
  577. fixed (byte* _bytes = &buffer[offset])
  578. {
  579. byte* bytes = _bytes;
  580. byte* bytesMax = &bytes[buffer.Length - offset];
  581. char* charsMax = &chars[charCount];
  582. while (true)
  583. {
  584. while (chars < charsMax)
  585. {
  586. char t = *chars;
  587. if (t >= 0x80)
  588. break;
  589. *bytes = (byte)t;
  590. bytes++;
  591. chars++;
  592. }
  593. if (chars >= charsMax)
  594. break;
  595. char* charsStart = chars;
  596. while (chars < charsMax && *chars >= 0x80)
  597. {
  598. chars++;
  599. }
  600. bytes += encoding.GetBytes(charsStart, (int)(chars - charsStart), bytes, (int)(bytesMax - bytes));
  601. if (chars >= charsMax)
  602. break;
  603. }
  604. return (int)(bytes - _bytes);
  605. }
  606. }
  607. return 0;
  608. }
  609. protected virtual void FlushBuffer()
  610. {
  611. if (offset != 0)
  612. {
  613. stream.Write(buffer, 0, offset);
  614. offset = 0;
  615. }
  616. }
  617. protected virtual IAsyncResult BeginFlushBuffer(AsyncCallback callback, object state)
  618. {
  619. return new FlushBufferAsyncResult(this, callback, state);
  620. }
  621. protected virtual void EndFlushBuffer(IAsyncResult result)
  622. {
  623. FlushBufferAsyncResult.End(result);
  624. }
  625. class FlushBufferAsyncResult : AsyncResult
  626. {
  627. static AsyncCompletion onComplete = new AsyncCompletion(OnComplete);
  628. XmlStreamNodeWriter writer;
  629. public FlushBufferAsyncResult(XmlStreamNodeWriter writer, AsyncCallback callback, object state)
  630. : base(callback, state)
  631. {
  632. this.writer = writer;
  633. bool completeSelf = true;
  634. if (writer.offset != 0)
  635. {
  636. completeSelf = HandleFlushBuffer(null);
  637. }
  638. if (completeSelf)
  639. {
  640. this.Complete(true);
  641. }
  642. }
  643. static bool OnComplete(IAsyncResult result)
  644. {
  645. FlushBufferAsyncResult thisPtr = (FlushBufferAsyncResult)result.AsyncState;
  646. return thisPtr.HandleFlushBuffer(result);
  647. }
  648. bool HandleFlushBuffer(IAsyncResult result)
  649. {
  650. if (result == null)
  651. {
  652. result = this.writer.stream.BeginWrite(writer.buffer, 0, writer.offset, PrepareAsyncCompletion(onComplete), this);
  653. if (!result.CompletedSynchronously)
  654. {
  655. return false;
  656. }
  657. }
  658. this.writer.stream.EndWrite(result);
  659. this.writer.offset = 0;
  660. return true;
  661. }
  662. public static void End(IAsyncResult result)
  663. {
  664. AsyncResult.End<FlushBufferAsyncResult>(result);
  665. }
  666. }
  667. public override void Flush()
  668. {
  669. FlushBuffer();
  670. stream.Flush();
  671. }
  672. public override void Close()
  673. {
  674. if (stream != null)
  675. {
  676. if (ownsStream)
  677. {
  678. stream.Close();
  679. }
  680. stream = null;
  681. }
  682. }
  683. internal class GetBufferArgs
  684. {
  685. public int Count { get; set; }
  686. }
  687. internal class GetBufferEventResult
  688. {
  689. internal byte[] Buffer { get; set; }
  690. internal int Offset { get; set; }
  691. }
  692. internal class GetBufferAsyncEventArgs : AsyncEventArgs<GetBufferArgs, GetBufferEventResult>
  693. {
  694. }
  695. }
  696. }