[bcl] Remove NET_4_0 defines from class libs.
[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, Encoding.UTF8UnmarkedUnsafe)
55                 {
56                 }
57
58                 public BinaryWriter(Stream output) : this(output, Encoding.UTF8UnmarkedUnsafe)
59                 {
60                 }
61                 
62 #if NET_4_5
63                 readonly bool leave_open;
64                 
65                 public BinaryWriter(Stream output, Encoding encoding)
66                         : this (output, encoding, false)
67                 {
68                 }
69                 
70                 public BinaryWriter(Stream output, Encoding encoding, bool leaveOpen)
71 #else
72                 const bool leave_open = false;
73                 
74                 public BinaryWriter(Stream output, Encoding encoding)
75 #endif
76                 {
77                         if (output == null) 
78                                 throw new ArgumentNullException("output");
79                         if (encoding == null) 
80                                 throw new ArgumentNullException("encoding");
81                         if (!output.CanWrite)
82                                 throw new ArgumentException(Locale.GetText ("Stream does not support writing or already closed."));
83
84 #if NET_4_5
85                         leave_open = leaveOpen;
86 #endif
87                         OutStream = output;
88                         m_encoding = encoding;
89                         buffer = new byte [16];
90                 }
91
92                 public virtual Stream BaseStream {
93                         get {
94                                 Flush ();
95                                 return OutStream;
96                         }
97                 }
98
99                 public virtual void Close() {
100                         Dispose (true);
101                 }
102
103                 public void Dispose ()
104                 {
105                         Dispose (true);
106                 }
107
108                 protected virtual void Dispose (bool disposing)
109                 {
110                         if (disposing && OutStream != null && !leave_open)
111                                 OutStream.Close();
112                         
113                         buffer = null;
114                         m_encoding = null;
115                         disposed = true;
116                 }
117
118                 public virtual void Flush() {
119                         OutStream.Flush();
120                 }
121
122                 public virtual long Seek(int offset, SeekOrigin origin) {
123
124                         return OutStream.Seek(offset, origin);
125                 }
126
127                 public virtual void Write(bool value) {
128
129                         if (disposed)
130                                 throw new ObjectDisposedException ("BinaryWriter", "Cannot write to a closed BinaryWriter");
131
132                         buffer [0] = (byte) (value ? 1 : 0);
133                         OutStream.Write(buffer, 0, 1);
134                 }
135
136                 public virtual void Write(byte value) {
137
138                         if (disposed)
139                                 throw new ObjectDisposedException ("BinaryWriter", "Cannot write to a closed BinaryWriter");
140
141                         OutStream.WriteByte(value);
142                 }
143
144                 public virtual void Write(byte[] buffer) {
145
146                         if (disposed)
147                                 throw new ObjectDisposedException ("BinaryWriter", "Cannot write to a closed BinaryWriter");
148
149                         if (buffer == null)
150                                 throw new ArgumentNullException("buffer");
151                         OutStream.Write(buffer, 0, buffer.Length);
152                 }
153
154                 public virtual void Write(byte[] buffer, int index, int count) {
155
156                         if (disposed)
157                                 throw new ObjectDisposedException ("BinaryWriter", "Cannot write to a closed BinaryWriter");
158
159                         if (buffer == null)
160                                 throw new ArgumentNullException("buffer");
161                         OutStream.Write(buffer, index, count);
162                 }
163
164                 public virtual void Write(char ch) {
165
166                         if (disposed)
167                                 throw new ObjectDisposedException ("BinaryWriter", "Cannot write to a closed BinaryWriter");
168
169                         char[] dec = new char[1];
170                         dec[0] = ch;
171                         byte[] enc = m_encoding.GetBytes(dec, 0, 1);
172                         OutStream.Write(enc, 0, enc.Length);
173                 }
174                 
175                 public virtual void Write(char[] chars) {
176
177                         if (disposed)
178                                 throw new ObjectDisposedException ("BinaryWriter", "Cannot write to a closed BinaryWriter");
179
180                         if (chars == null)
181                                 throw new ArgumentNullException("chars");
182                         byte[] enc = m_encoding.GetBytes(chars, 0, chars.Length);
183                         OutStream.Write(enc, 0, enc.Length);
184                 }
185
186                 public virtual void Write(char[] chars, int index, int count) {
187
188                         if (disposed)
189                                 throw new ObjectDisposedException ("BinaryWriter", "Cannot write to a closed BinaryWriter");
190
191                         if (chars == null)
192                                 throw new ArgumentNullException("chars");
193                         byte[] enc = m_encoding.GetBytes(chars, index, count);
194                         OutStream.Write(enc, 0, enc.Length);
195                 }
196
197                 unsafe public virtual void Write(decimal value) {
198
199                         if (disposed)
200                                 throw new ObjectDisposedException ("BinaryWriter", "Cannot write to a closed BinaryWriter");
201
202                         byte* value_ptr = (byte *)&value;
203                         
204                         /*
205                          * decimal in stream is lo32, mi32, hi32, ss32
206                          * but its internal structure si ss32, hi32, lo32, mi32
207                          */
208                                  
209                         if (BitConverter.IsLittleEndian) {
210                                 for (int i = 0; i < 16; i++) {
211                                         if (i < 4) 
212                                                 buffer [i + 12] = value_ptr [i];
213                                         else if (i < 8)
214                                                 buffer [i + 4] = value_ptr [i];
215                                         else if (i < 12)
216                                                 buffer [i - 8] = value_ptr [i];
217                                         else 
218                                                 buffer [i - 8] = value_ptr [i];
219                                 }
220                         } else {
221                                 for (int i = 0; i < 16; i++) {
222                                         if (i < 4) 
223                                                 buffer [15 - i] = value_ptr [i];
224                                         else if (i < 8)
225                                                 buffer [15 - i] = value_ptr [i];
226                                         else if (i < 12)
227                                                 buffer [11 - i] = value_ptr [i];
228                                         else 
229                                                 buffer [19 - i] = value_ptr [i];
230                                 }
231                         }
232
233                         OutStream.Write(buffer, 0, 16);
234                 }
235
236                 public virtual void Write(double value) {
237
238                         if (disposed)
239                                 throw new ObjectDisposedException ("BinaryWriter", "Cannot write to a closed BinaryWriter");
240
241                         OutStream.Write(BitConverterLE.GetBytes(value), 0, 8);
242                 }
243                 
244                 public virtual void Write(short value) {
245
246                         if (disposed)
247                                 throw new ObjectDisposedException ("BinaryWriter", "Cannot write to a closed BinaryWriter");
248
249                         buffer [0] = (byte) value;
250                         buffer [1] = (byte) (value >> 8);
251                         OutStream.Write(buffer, 0, 2);
252                 }
253                 
254                 public virtual void Write(int value) {
255
256                         if (disposed)
257                                 throw new ObjectDisposedException ("BinaryWriter", "Cannot write to a closed BinaryWriter");
258
259                         buffer [0] = (byte) value;
260                         buffer [1] = (byte) (value >> 8);
261                         buffer [2] = (byte) (value >> 16);
262                         buffer [3] = (byte) (value >> 24);
263                         OutStream.Write(buffer, 0, 4);
264                 }
265
266                 public virtual void Write(long value) {
267
268                         if (disposed)
269                                 throw new ObjectDisposedException ("BinaryWriter", "Cannot write to a closed BinaryWriter");
270
271                         for (int i = 0, sh = 0; i < 8; i++, sh += 8)
272                                 buffer [i] = (byte) (value >> sh);
273                         OutStream.Write(buffer, 0, 8);
274                 }
275
276                 [CLSCompliant(false)]
277                 public virtual void Write(sbyte value) {
278
279                         if (disposed)
280                                 throw new ObjectDisposedException ("BinaryWriter", "Cannot write to a closed BinaryWriter");
281
282                         buffer [0] = (byte) value;
283                         OutStream.Write(buffer, 0, 1);
284                 }
285
286                 public virtual void Write(float value) {
287
288                         if (disposed)
289                                 throw new ObjectDisposedException ("BinaryWriter", "Cannot write to a closed BinaryWriter");
290
291                         OutStream.Write(BitConverterLE.GetBytes(value), 0, 4);
292                 }
293                 
294                 public virtual void Write(string value) {
295
296                         if (disposed)
297                                 throw new ObjectDisposedException ("BinaryWriter", "Cannot write to a closed BinaryWriter");
298
299                         int len = m_encoding.GetByteCount (value);
300                         Write7BitEncodedInt (len);
301                         
302                         if (stringBuffer == null) {
303                                 stringBuffer = new byte [512];
304                                 maxCharsPerRound = 512 / m_encoding.GetMaxByteCount (1);
305                         }
306                         
307                         int chpos = 0;
308                         int chrem = value.Length;
309                         while (chrem > 0) {
310                                 int cch = (chrem > maxCharsPerRound) ? maxCharsPerRound : chrem;
311                                 int blen = m_encoding.GetBytes (value, chpos, cch, stringBuffer, 0);
312                                 OutStream.Write (stringBuffer, 0, blen);
313                                 
314                                 chpos += cch;
315                                 chrem -= cch;
316                         }
317                 }
318
319                 [CLSCompliant(false)]
320                 public virtual void Write(ushort value) {
321
322                         if (disposed)
323                                 throw new ObjectDisposedException ("BinaryWriter", "Cannot write to a closed BinaryWriter");
324
325                         buffer [0] = (byte) value;
326                         buffer [1] = (byte) (value >> 8);
327                         OutStream.Write(buffer, 0, 2);
328                 }
329
330                 [CLSCompliant(false)]
331                 public virtual void Write(uint value) {
332
333                         if (disposed)
334                                 throw new ObjectDisposedException ("BinaryWriter", "Cannot write to a closed BinaryWriter");
335
336                         buffer [0] = (byte) value;
337                         buffer [1] = (byte) (value >> 8);
338                         buffer [2] = (byte) (value >> 16);
339                         buffer [3] = (byte) (value >> 24);
340                         OutStream.Write(buffer, 0, 4);
341                 }
342
343                 [CLSCompliant(false)]
344                 public virtual void Write(ulong value) {
345
346                         if (disposed)
347                                 throw new ObjectDisposedException ("BinaryWriter", "Cannot write to a closed BinaryWriter");
348
349                         for (int i = 0, sh = 0; i < 8; i++, sh += 8)
350                                 buffer [i] = (byte) (value >> sh);
351                         OutStream.Write(buffer, 0, 8);
352                 }
353
354                 protected void Write7BitEncodedInt(int value) {
355                         do {
356                                 int high = (value >> 7) & 0x01ffffff;
357                                 byte b = (byte)(value & 0x7f);
358
359                                 if (high != 0) {
360                                         b = (byte)(b | 0x80);
361                                 }
362
363                                 Write(b);
364                                 value = high;
365                         } while(value != 0);
366                 }
367         }
368 }