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