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