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