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