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