X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fclass%2Fcorlib%2FSystem.IO%2FStreamWriter.cs;h=fe3a606261730cd522bea0648a95c3deb600117e;hb=cbbd71101794e66ab7477db65cfbd61d67e08305;hp=4a672776ac1616bbe04f4814d0f77acc1d16dd9f;hpb=8d3024b0868958cfca3b796ef58ab5f285145cba;p=mono.git diff --git a/mcs/class/corlib/System.IO/StreamWriter.cs b/mcs/class/corlib/System.IO/StreamWriter.cs index 4a672776ac1..fe3a6062617 100644 --- a/mcs/class/corlib/System.IO/StreamWriter.cs +++ b/mcs/class/corlib/System.IO/StreamWriter.cs @@ -4,12 +4,11 @@ // Authors: // Dietmar Maurer (dietmar@ximian.com) // Paolo Molaro (lupus@ximian.com) +// Marek Safar (marek.safar@gmail.com) // // (C) Ximian, Inc. http://www.ximian.com -// - -// // Copyright (C) 2004 Novell, Inc (http://www.novell.com) +// Copyright 2011, 2013 Xamarin Inc. // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the @@ -32,39 +31,38 @@ // using System.Text; -using System; - -#if NET_2_0 using System.Runtime.InteropServices; +#if NET_4_5 +using System.Threading.Tasks; #endif namespace System.IO { [Serializable] -#if NET_2_0 [ComVisible (true)] -#endif public class StreamWriter : TextWriter { private Encoding internalEncoding; private Stream internalStream; - private bool closed; - private bool iflush; - private const int DefaultBufferSize = 1024; private const int DefaultFileBufferSize = 4096; private const int MinimumBufferSize = 256; private byte[] byte_buf; - private int byte_pos; private char[] decode_buf; + private int byte_pos; private int decode_pos; - private bool DisposedAlready; + private bool iflush; private bool preamble_done; +#if NET_4_5 + readonly bool leave_open; + IDecoupledTask async_task; +#endif + public new static readonly StreamWriter Null = new StreamWriter (Stream.Null, Encoding.UTF8Unmarked, 1); public StreamWriter (Stream stream) @@ -85,7 +83,19 @@ namespace System.IO { preamble_done = true; } - public StreamWriter (Stream stream, Encoding encoding, int bufferSize) { +#if NET_4_5 + public StreamWriter (Stream stream, Encoding encoding, int bufferSize) + : this (stream, encoding, bufferSize, false) + { + } + + public StreamWriter (Stream stream, Encoding encoding, int bufferSize, bool leaveOpen) +#else + const bool leave_open = false; + + public StreamWriter (Stream stream, Encoding encoding, int bufferSize) +#endif + { if (null == stream) throw new ArgumentNullException("stream"); if (null == encoding) @@ -95,6 +105,9 @@ namespace System.IO { if (!stream.CanWrite) throw new ArgumentException ("Can not write to stream"); +#if NET_4_5 + leave_open = leaveOpen; +#endif internalStream = stream; Initialize(encoding, bufferSize); @@ -108,8 +121,9 @@ namespace System.IO { public StreamWriter (string path, bool append, Encoding encoding) : this (path, append, encoding, DefaultFileBufferSize) {} - - public StreamWriter (string path, bool append, Encoding encoding, int bufferSize) { + + public StreamWriter (string path, bool append, Encoding encoding, int bufferSize) + { if (null == encoding) throw new ArgumentNullException("encoding"); if (bufferSize <= 0) @@ -157,23 +171,33 @@ namespace System.IO { protected override void Dispose (bool disposing) { - if (!DisposedAlready && disposing && internalStream != null) { - Flush(); - DisposedAlready = true; - internalStream.Close (); - } + if (byte_buf == null || !disposing) + return; - internalStream = null; - byte_buf = null; - internalEncoding = null; - decode_buf = null; + try { + Flush (); + } finally { + byte_buf = null; + internalEncoding = null; + decode_buf = null; + + if (!leave_open) { + internalStream.Close (); + } + + internalStream = null; + } } public override void Flush () { - if (DisposedAlready) - throw new ObjectDisposedException("StreamWriter"); + CheckState (); + FlushCore (); + } + // Keep in sync with FlushCoreAsync + void FlushCore () + { Decode (); if (byte_pos > 0) { FlushBytes (); @@ -198,7 +222,7 @@ namespace System.IO { internalStream.Write (byte_buf, 0, byte_pos); byte_pos = 0; } - + void Decode () { if (byte_pos > 0) @@ -209,26 +233,7 @@ namespace System.IO { decode_pos = 0; } } - - public override void Write (char[] buffer, int index, int count) - { - if (DisposedAlready) - throw new ObjectDisposedException("StreamWriter"); - if (buffer == null) - throw new ArgumentNullException ("buffer"); - if (index < 0) - throw new ArgumentOutOfRangeException ("index", "< 0"); - if (count < 0) - throw new ArgumentOutOfRangeException ("count", "< 0"); - // re-ordered to avoid possible integer overflow - if (index > buffer.Length - count) - throw new ArgumentException ("index + count > buffer.Length"); - LowLevelWrite (buffer, index, count); - if (iflush) - Flush(); - } - void LowLevelWrite (char[] buffer, int index, int count) { while (count > 0) { @@ -266,12 +271,105 @@ namespace System.IO { index += todo; decode_pos += todo; } + } + +#if NET_4_5 + async Task FlushCoreAsync () + { + await DecodeAsync ().ConfigureAwait (false); + if (byte_pos > 0) { + await FlushBytesAsync ().ConfigureAwait (false); + await internalStream.FlushAsync ().ConfigureAwait (false); + } + } + + async Task FlushBytesAsync () + { + // write the encoding preamble only at the start of the stream + if (!preamble_done && byte_pos > 0) { + byte[] preamble = internalEncoding.GetPreamble (); + if (preamble.Length > 0) + await internalStream.WriteAsync (preamble, 0, preamble.Length).ConfigureAwait (false); + preamble_done = true; + } + + await internalStream.WriteAsync (byte_buf, 0, byte_pos).ConfigureAwait (false); + byte_pos = 0; + } + + async Task DecodeAsync () + { + if (byte_pos > 0) + await FlushBytesAsync ().ConfigureAwait (false); + if (decode_pos > 0) { + int len = internalEncoding.GetBytes (decode_buf, 0, decode_pos, byte_buf, byte_pos); + byte_pos += len; + decode_pos = 0; + } + } + + async Task LowLevelWriteAsync (char[] buffer, int index, int count) + { + while (count > 0) { + int todo = decode_buf.Length - decode_pos; + if (todo == 0) { + await DecodeAsync ().ConfigureAwait (false); + todo = decode_buf.Length; + } + if (todo > count) + todo = count; + Buffer.BlockCopy (buffer, index * 2, decode_buf, decode_pos * 2, todo * 2); + count -= todo; + index += todo; + decode_pos += todo; + } } + + async Task LowLevelWriteAsync (string s) + { + int count = s.Length; + int index = 0; + while (count > 0) { + int todo = decode_buf.Length - decode_pos; + if (todo == 0) { + await DecodeAsync ().ConfigureAwait (false); + todo = decode_buf.Length; + } + if (todo > count) + todo = count; + + for (int i = 0; i < todo; i ++) + decode_buf [i + decode_pos] = s [i + index]; + + count -= todo; + index += todo; + decode_pos += todo; + } + } +#endif + + public override void Write (char[] buffer, int index, int count) + { + if (buffer == null) + throw new ArgumentNullException ("buffer"); + if (index < 0) + throw new ArgumentOutOfRangeException ("index", "< 0"); + if (count < 0) + throw new ArgumentOutOfRangeException ("count", "< 0"); + // re-ordered to avoid possible integer overflow + if (index > buffer.Length - count) + throw new ArgumentException ("index + count > buffer.Length"); + CheckState (); + + LowLevelWrite (buffer, index, count); + if (iflush) + FlushCore (); + } + public override void Write (char value) { - if (DisposedAlready) - throw new ObjectDisposedException("StreamWriter"); + CheckState (); // the size of decode_buf is always > 0 and // we check for overflow right away @@ -279,41 +377,188 @@ namespace System.IO { Decode (); decode_buf [decode_pos++] = value; if (iflush) - Flush (); + FlushCore (); } public override void Write (char[] buffer) { - if (DisposedAlready) - throw new ObjectDisposedException ("StreamWriter"); + CheckState (); if (buffer != null) LowLevelWrite (buffer, 0, buffer.Length); if (iflush) - Flush (); + FlushCore (); } public override void Write (string value) { - if (DisposedAlready) - throw new ObjectDisposedException("StreamWriter"); + CheckState (); - if (value != null) - LowLevelWrite (value); + if (value == null) + return; + + LowLevelWrite (value); if (iflush) - Flush (); + FlushCore (); } public override void Close() { - closed = true; Dispose (true); } - ~StreamWriter () + void CheckState () + { + if (byte_buf == null) + throw new ObjectDisposedException ("StreamWriter"); + +#if NET_4_5 + if (async_task != null && !async_task.IsCompleted) + throw new InvalidOperationException (); +#endif + } + +#if NET_4_5 + public override Task FlushAsync () { - Dispose(false); + CheckState (); + DecoupledTask res; + async_task = res = new DecoupledTask (FlushCoreAsync ()); + return res.Task; + } + + public override Task WriteAsync (char value) + { + CheckState (); + + DecoupledTask res; + async_task = res = new DecoupledTask (WriteAsyncCore (value)); + return res.Task; + } + + async Task WriteAsyncCore (char value) + { + // the size of decode_buf is always > 0 and + // we check for overflow right away + if (decode_pos >= decode_buf.Length) + await DecodeAsync ().ConfigureAwait (false); + decode_buf [decode_pos++] = value; + + if (iflush) + await FlushCoreAsync ().ConfigureAwait (false); + } + + public override Task WriteAsync (char[] buffer, int index, int count) + { + CheckState (); + if (buffer == null) + return TaskConstants.Finished; + + DecoupledTask res; + async_task = res = new DecoupledTask (WriteAsyncCore (buffer, index, count)); + return res.Task; } + + async Task WriteAsyncCore (char[] buffer, int index, int count) + { + // Debug.Assert (buffer == null); + + await LowLevelWriteAsync (buffer, index, count).ConfigureAwait (false); + + if (iflush) + await FlushCoreAsync ().ConfigureAwait (false); + } + + public override Task WriteAsync (string value) + { + CheckState (); + + if (value == null) + return TaskConstants.Finished; + + DecoupledTask res; + async_task = res = new DecoupledTask (WriteAsyncCore (value, false)); + return res.Task; + } + + async Task WriteAsyncCore (string value, bool appendNewLine) + { + // Debug.Assert (value == null); + + await LowLevelWriteAsync (value).ConfigureAwait (false); + if (appendNewLine) + await LowLevelWriteAsync (CoreNewLine, 0, CoreNewLine.Length).ConfigureAwait (false); + + if (iflush) + await FlushCoreAsync ().ConfigureAwait (false); + } + + public override Task WriteLineAsync () + { + CheckState (); + + DecoupledTask res; + async_task = res = new DecoupledTask (WriteAsyncCore (CoreNewLine, 0, CoreNewLine.Length)); + return res.Task; + } + + public override Task WriteLineAsync (char value) + { + CheckState (); + DecoupledTask res; + async_task = res = new DecoupledTask (WriteLineAsyncCore (value)); + return res.Task; + } + + async Task WriteLineAsyncCore (char value) + { + await WriteAsyncCore (value).ConfigureAwait (false); + await LowLevelWriteAsync (CoreNewLine, 0, CoreNewLine.Length).ConfigureAwait (false); + + if (iflush) + await FlushCoreAsync ().ConfigureAwait (false); + } + + public override Task WriteLineAsync (char[] buffer, int index, int count) + { + if (buffer == null) + throw new ArgumentNullException ("buffer"); + if (index < 0) + throw new ArgumentOutOfRangeException ("index", "< 0"); + if (count < 0) + throw new ArgumentOutOfRangeException ("count", "< 0"); + // re-ordered to avoid possible integer overflow + if (index > buffer.Length - count) + throw new ArgumentException ("index + count > buffer.Length"); + + CheckState (); + DecoupledTask res; + async_task = res = new DecoupledTask (WriteLineAsyncCore (buffer, index, count)); + return res.Task; + } + + async Task WriteLineAsyncCore (char[] buffer, int index, int count) + { + // Debug.Assert (buffer == null); + + await LowLevelWriteAsync (buffer, index, count).ConfigureAwait (false); + await LowLevelWriteAsync (CoreNewLine, 0, CoreNewLine.Length).ConfigureAwait (false); + + if (iflush) + await FlushCoreAsync ().ConfigureAwait (false); + } + + public override Task WriteLineAsync (string value) + { + if (value == null) + return WriteLineAsync (); + + CheckState (); + DecoupledTask res; + async_task = res = new DecoupledTask (WriteAsyncCore (value, true)); + return res.Task; + } +#endif } }