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