Merge pull request #1563 from directhex/emit-nunit-xml-in-unmanaged-tests
[mono.git] / mcs / class / corlib / System.IO / BinaryWriter.cs
1 //
2 // System.IO.BinaryWriter
3 //
4 // Authors:
5 //   Matt Kimball (matt@kimball.net)
6 //   Marek Safar (marek.safar@gmail.com)
7 //
8
9 //
10 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
11 // Copyright 2011 Xamarin Inc.
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
20 // 
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
23 // 
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 //
32
33 using System;
34 using System.Text;
35 using System.Globalization;
36 using Mono.Security;
37 using System.Runtime.InteropServices;
38
39 namespace System.IO {
40         [Serializable]
41         [ComVisible (true)]
42         public class BinaryWriter : IDisposable {
43
44                 // Null is a BinaryWriter with no backing store.
45                 public static readonly BinaryWriter Null = new BinaryWriter ();
46
47                 protected Stream OutStream;
48                 private Encoding m_encoding;
49                 private byte [] buffer;
50                 byte [] stringBuffer;
51                 int maxCharsPerRound;
52                 bool disposed;
53
54                 protected BinaryWriter() : this (Stream.Null, EncodingHelper.UTF8UnmarkedUnsafe)
55                 {
56                 }
57
58                 public BinaryWriter(Stream output) : this(output, EncodingHelper.UTF8UnmarkedUnsafe)
59                 {
60                 }
61                 
62                 readonly bool leave_open;
63                 
64                 public BinaryWriter(Stream output, Encoding encoding)
65                         : this (output, encoding, false)
66                 {
67                 }
68                 
69                 public BinaryWriter(Stream output, Encoding encoding, bool leaveOpen)
70                 {
71                         if (output == null) 
72                                 throw new ArgumentNullException("output");
73                         if (encoding == null) 
74                                 throw new ArgumentNullException("encoding");
75                         if (!output.CanWrite)
76                                 throw new ArgumentException(Locale.GetText ("Stream does not support writing or already closed."));
77
78                         leave_open = leaveOpen;
79                         OutStream = output;
80                         m_encoding = encoding;
81                         buffer = new byte [16];
82                 }
83
84                 public virtual Stream BaseStream {
85                         get {
86                                 Flush ();
87                                 return OutStream;
88                         }
89                 }
90
91                 public virtual void Close() {
92                         Dispose (true);
93                 }
94
95                 public void Dispose ()
96                 {
97                         Dispose (true);
98                 }
99
100                 protected virtual void Dispose (bool disposing)
101                 {
102                         if (disposing && OutStream != null && !leave_open)
103                                 OutStream.Close();
104                         
105                         buffer = null;
106                         m_encoding = null;
107                         disposed = true;
108                 }
109
110                 public virtual void Flush() {
111                         OutStream.Flush();
112                 }
113
114                 public virtual long Seek(int offset, SeekOrigin origin) {
115
116                         return OutStream.Seek(offset, origin);
117                 }
118
119                 public virtual void Write(bool value) {
120
121                         if (disposed)
122                                 throw new ObjectDisposedException ("BinaryWriter", "Cannot write to a closed BinaryWriter");
123
124                         buffer [0] = (byte) (value ? 1 : 0);
125                         OutStream.Write(buffer, 0, 1);
126                 }
127
128                 public virtual void Write(byte value) {
129
130                         if (disposed)
131                                 throw new ObjectDisposedException ("BinaryWriter", "Cannot write to a closed BinaryWriter");
132
133                         OutStream.WriteByte(value);
134                 }
135
136                 public virtual void Write(byte[] buffer) {
137
138                         if (disposed)
139                                 throw new ObjectDisposedException ("BinaryWriter", "Cannot write to a closed BinaryWriter");
140
141                         if (buffer == null)
142                                 throw new ArgumentNullException("buffer");
143                         OutStream.Write(buffer, 0, buffer.Length);
144                 }
145
146                 public virtual void Write(byte[] buffer, int index, int count) {
147
148                         if (disposed)
149                                 throw new ObjectDisposedException ("BinaryWriter", "Cannot write to a closed BinaryWriter");
150
151                         if (buffer == null)
152                                 throw new ArgumentNullException("buffer");
153                         OutStream.Write(buffer, index, count);
154                 }
155
156                 public virtual void Write(char ch) {
157
158                         if (disposed)
159                                 throw new ObjectDisposedException ("BinaryWriter", "Cannot write to a closed BinaryWriter");
160
161                         char[] dec = new char[1];
162                         dec[0] = ch;
163                         byte[] enc = m_encoding.GetBytes(dec, 0, 1);
164                         OutStream.Write(enc, 0, enc.Length);
165                 }
166                 
167                 public virtual void Write(char[] chars) {
168
169                         if (disposed)
170                                 throw new ObjectDisposedException ("BinaryWriter", "Cannot write to a closed BinaryWriter");
171
172                         if (chars == null)
173                                 throw new ArgumentNullException("chars");
174                         byte[] enc = m_encoding.GetBytes(chars, 0, chars.Length);
175                         OutStream.Write(enc, 0, enc.Length);
176                 }
177
178                 public virtual void Write(char[] chars, int index, int count) {
179
180                         if (disposed)
181                                 throw new ObjectDisposedException ("BinaryWriter", "Cannot write to a closed BinaryWriter");
182
183                         if (chars == null)
184                                 throw new ArgumentNullException("chars");
185                         byte[] enc = m_encoding.GetBytes(chars, index, count);
186                         OutStream.Write(enc, 0, enc.Length);
187                 }
188
189                 unsafe public virtual void Write(decimal value) {
190
191                         if (disposed)
192                                 throw new ObjectDisposedException ("BinaryWriter", "Cannot write to a closed BinaryWriter");
193
194                         byte* value_ptr = (byte *)&value;
195                         
196                         /*
197                          * decimal in stream is lo32, mi32, hi32, ss32
198                          * but its internal structure si ss32, hi32, lo32, mi32
199                          */
200                                  
201                         if (BitConverter.IsLittleEndian) {
202                                 for (int i = 0; i < 16; i++) {
203                                         if (i < 4) 
204                                                 buffer [i + 12] = value_ptr [i];
205                                         else if (i < 8)
206                                                 buffer [i + 4] = value_ptr [i];
207                                         else if (i < 12)
208                                                 buffer [i - 8] = value_ptr [i];
209                                         else 
210                                                 buffer [i - 8] = value_ptr [i];
211                                 }
212                         } else {
213                                 for (int i = 0; i < 16; i++) {
214                                         if (i < 4) 
215                                                 buffer [15 - i] = value_ptr [i];
216                                         else if (i < 8)
217                                                 buffer [15 - i] = value_ptr [i];
218                                         else if (i < 12)
219                                                 buffer [11 - i] = value_ptr [i];
220                                         else 
221                                                 buffer [19 - i] = value_ptr [i];
222                                 }
223                         }
224
225                         OutStream.Write(buffer, 0, 16);
226                 }
227
228                 public virtual void Write(double value) {
229
230                         if (disposed)
231                                 throw new ObjectDisposedException ("BinaryWriter", "Cannot write to a closed BinaryWriter");
232
233                         OutStream.Write(BitConverterLE.GetBytes(value), 0, 8);
234                 }
235                 
236                 public virtual void Write(short value) {
237
238                         if (disposed)
239                                 throw new ObjectDisposedException ("BinaryWriter", "Cannot write to a closed BinaryWriter");
240
241                         buffer [0] = (byte) value;
242                         buffer [1] = (byte) (value >> 8);
243                         OutStream.Write(buffer, 0, 2);
244                 }
245                 
246                 public virtual void Write(int value) {
247
248                         if (disposed)
249                                 throw new ObjectDisposedException ("BinaryWriter", "Cannot write to a closed BinaryWriter");
250
251                         buffer [0] = (byte) value;
252                         buffer [1] = (byte) (value >> 8);
253                         buffer [2] = (byte) (value >> 16);
254                         buffer [3] = (byte) (value >> 24);
255                         OutStream.Write(buffer, 0, 4);
256                 }
257
258                 public virtual void Write(long value) {
259
260                         if (disposed)
261                                 throw new ObjectDisposedException ("BinaryWriter", "Cannot write to a closed BinaryWriter");
262
263                         for (int i = 0, sh = 0; i < 8; i++, sh += 8)
264                                 buffer [i] = (byte) (value >> sh);
265                         OutStream.Write(buffer, 0, 8);
266                 }
267
268                 [CLSCompliant(false)]
269                 public virtual void Write(sbyte value) {
270
271                         if (disposed)
272                                 throw new ObjectDisposedException ("BinaryWriter", "Cannot write to a closed BinaryWriter");
273
274                         buffer [0] = (byte) value;
275                         OutStream.Write(buffer, 0, 1);
276                 }
277
278                 public virtual void Write(float value) {
279
280                         if (disposed)
281                                 throw new ObjectDisposedException ("BinaryWriter", "Cannot write to a closed BinaryWriter");
282
283                         OutStream.Write(BitConverterLE.GetBytes(value), 0, 4);
284                 }
285                 
286                 public virtual void Write(string value) {
287
288                         if (disposed)
289                                 throw new ObjectDisposedException ("BinaryWriter", "Cannot write to a closed BinaryWriter");
290
291                         int len = m_encoding.GetByteCount (value);
292                         Write7BitEncodedInt (len);
293                         
294                         if (stringBuffer == null) {
295                                 stringBuffer = new byte [512];
296                                 maxCharsPerRound = 512 / m_encoding.GetMaxByteCount (1);
297                         }
298                         
299                         int chpos = 0;
300                         int chrem = value.Length;
301                         while (chrem > 0) {
302                                 int cch = (chrem > maxCharsPerRound) ? maxCharsPerRound : chrem;
303                                 int blen = m_encoding.GetBytes (value, chpos, cch, stringBuffer, 0);
304                                 OutStream.Write (stringBuffer, 0, blen);
305                                 
306                                 chpos += cch;
307                                 chrem -= cch;
308                         }
309                 }
310
311                 [CLSCompliant(false)]
312                 public virtual void Write(ushort value) {
313
314                         if (disposed)
315                                 throw new ObjectDisposedException ("BinaryWriter", "Cannot write to a closed BinaryWriter");
316
317                         buffer [0] = (byte) value;
318                         buffer [1] = (byte) (value >> 8);
319                         OutStream.Write(buffer, 0, 2);
320                 }
321
322                 [CLSCompliant(false)]
323                 public virtual void Write(uint value) {
324
325                         if (disposed)
326                                 throw new ObjectDisposedException ("BinaryWriter", "Cannot write to a closed BinaryWriter");
327
328                         buffer [0] = (byte) value;
329                         buffer [1] = (byte) (value >> 8);
330                         buffer [2] = (byte) (value >> 16);
331                         buffer [3] = (byte) (value >> 24);
332                         OutStream.Write(buffer, 0, 4);
333                 }
334
335                 [CLSCompliant(false)]
336                 public virtual void Write(ulong value) {
337
338                         if (disposed)
339                                 throw new ObjectDisposedException ("BinaryWriter", "Cannot write to a closed BinaryWriter");
340
341                         for (int i = 0, sh = 0; i < 8; i++, sh += 8)
342                                 buffer [i] = (byte) (value >> sh);
343                         OutStream.Write(buffer, 0, 8);
344                 }
345
346                 protected void Write7BitEncodedInt(int value) {
347                         do {
348                                 int high = (value >> 7) & 0x01ffffff;
349                                 byte b = (byte)(value & 0x7f);
350
351                                 if (high != 0) {
352                                         b = (byte)(b | 0x80);
353                                 }
354
355                                 Write(b);
356                                 value = high;
357                         } while(value != 0);
358                 }
359         }
360 }