大连中石油电子沙盘
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

429 lines
13 KiB

// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.IO;
using System.Text;
using System.Diagnostics;
// This abstract base class represents a writer that can write
// primitives to an arbitrary stream. A subclass can override methods to
// give unique encodings.
//
internal class BinaryWriter : IDisposable
{
public static readonly BinaryWriter Null = new BinaryWriter();
protected Stream OutStream;
private byte[] _buffer; // temp space for writing primitives to.
private Encoding _encoding;
private Encoder _encoder;
private bool _leaveOpen;
// Perf optimization stuff
private byte[] _largeByteBuffer; // temp space for writing chars.
private int _maxChars; // max # of chars we can put in _largeByteBuffer
// Size should be around the max number of chars/string * Encoding's max bytes/char
private const int LargeByteBufferSize = 256;
// Protected default constructor that sets the output stream
// to a null stream (a bit bucket).
protected BinaryWriter()
{
OutStream = Stream.Null;
_buffer = new byte[16];
_encoding = new UTF8Encoding(false, true);
_encoder = _encoding.GetEncoder();
}
public BinaryWriter(Stream output) : this(output, new UTF8Encoding(false, true), false)
{
}
public BinaryWriter(Stream output, Encoding encoding) : this(output, encoding, false)
{
}
public BinaryWriter(Stream output, Encoding encoding, bool leaveOpen)
{
if (output == null)
{
throw new ArgumentNullException("output");
}
if (encoding == null)
{
throw new ArgumentNullException("encoding");
}
if (!output.CanWrite)
{
throw new ArgumentException("StreamNotWritable");
}
OutStream = output;
_buffer = new byte[16];
_encoding = encoding;
_encoder = _encoding.GetEncoder();
_leaveOpen = leaveOpen;
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (_leaveOpen)
{
OutStream.Flush();
}
else
{
OutStream.Dispose();
}
}
}
public void Dispose()
{
Dispose(true);
}
/*
* Returns the stream associate with the writer. It flushes all pending
* writes before returning. All subclasses should override Flush to
* ensure that all buffered data is sent to the stream.
*/
public virtual Stream BaseStream
{
get
{
Flush();
return OutStream;
}
}
// Clears all buffers for this writer and causes any buffered data to be
// written to the underlying device.
public virtual void Flush()
{
OutStream.Flush();
}
public virtual long Seek(int offset, SeekOrigin origin)
{
return OutStream.Seek(offset, origin);
}
// Writes a boolean to this stream. A single byte is written to the stream
// with the value 0 representing false or the value 1 representing true.
//
public virtual void Write(bool value)
{
_buffer[0] = (byte)(value ? 1 : 0);
OutStream.Write(_buffer, 0, 1);
}
// Writes a byte to this stream. The current position of the stream is
// advanced by one.
//
public virtual void Write(byte value)
{
OutStream.WriteByte(value);
}
// Writes a signed byte to this stream. The current position of the stream
// is advanced by one.
//
#pragma warning disable 3019, 3021
[CLSCompliant(false)]
public virtual void Write(sbyte value)
{
OutStream.WriteByte((byte)value);
}
#pragma warning restore 3019, 3021
// Writes a byte array to this stream.
//
// This default implementation calls the Write(Object, int, int)
// method to write the byte array.
//
public virtual void Write(byte[] buffer)
{
if (buffer == null)
{
throw new ArgumentNullException("buffer");
}
OutStream.Write(buffer, 0, buffer.Length);
}
// Writes a section of a byte array to this stream.
//
// This default implementation calls the Write(Object, int, int)
// method to write the byte array.
//
public virtual void Write(byte[] buffer, int index, int count)
{
OutStream.Write(buffer, index, count);
}
// Writes a character to this stream. The current position of the stream is
// advanced by two.
// Note this method cannot handle surrogates properly in UTF-8.
//
public unsafe virtual void Write(char ch)
{
if (char.IsSurrogate(ch))
{
throw new ArgumentException("SurrogatesNotAllowedAsSingleChar");
}
Debug.Assert(_encoding.GetMaxByteCount(1) <= 16, "_encoding.GetMaxByteCount(1) <= 16)");
int numBytes = 0;
char[] chBuf = new char[] { ch };
numBytes = _encoder.GetBytes(chBuf, 0, 1, _buffer, 0, true);
OutStream.Write(_buffer, 0, numBytes);
}
// Writes a character array to this stream.
//
// This default implementation calls the Write(Object, int, int)
// method to write the character array.
//
public virtual void Write(char[] chars)
{
if (chars == null)
{
throw new ArgumentNullException("chars");
}
byte[] bytes = _encoding.GetBytes(chars, 0, chars.Length);
OutStream.Write(bytes, 0, bytes.Length);
}
// Writes a section of a character array to this stream.
//
// This default implementation calls the Write(Object, int, int)
// method to write the character array.
//
public virtual void Write(char[] chars, int index, int count)
{
byte[] bytes = _encoding.GetBytes(chars, index, count);
OutStream.Write(bytes, 0, bytes.Length);
}
// Writes a double to this stream. The current position of the stream is
// advanced by eight.
//
public unsafe virtual void Write(double value)
{
ulong TmpValue = *(ulong*)&value;
_buffer[0] = (byte)TmpValue;
_buffer[1] = (byte)(TmpValue >> 8);
_buffer[2] = (byte)(TmpValue >> 16);
_buffer[3] = (byte)(TmpValue >> 24);
_buffer[4] = (byte)(TmpValue >> 32);
_buffer[5] = (byte)(TmpValue >> 40);
_buffer[6] = (byte)(TmpValue >> 48);
_buffer[7] = (byte)(TmpValue >> 56);
OutStream.Write(_buffer, 0, 8);
}
public virtual void Write(decimal value)
{
int[] bits = decimal.GetBits(value);
Debug.Assert(bits.Length == 4);
int lo = bits[0];
_buffer[0] = (byte)lo;
_buffer[1] = (byte)(lo >> 8);
_buffer[2] = (byte)(lo >> 16);
_buffer[3] = (byte)(lo >> 24);
int mid = bits[1];
_buffer[4] = (byte)mid;
_buffer[5] = (byte)(mid >> 8);
_buffer[6] = (byte)(mid >> 16);
_buffer[7] = (byte)(mid >> 24);
int hi = bits[2];
_buffer[8] = (byte)hi;
_buffer[9] = (byte)(hi >> 8);
_buffer[10] = (byte)(hi >> 16);
_buffer[11] = (byte)(hi >> 24);
int flags = bits[3];
_buffer[12] = (byte)flags;
_buffer[13] = (byte)(flags >> 8);
_buffer[14] = (byte)(flags >> 16);
_buffer[15] = (byte)(flags >> 24);
OutStream.Write(_buffer, 0, 16);
}
// Writes a two-byte signed integer to this stream. The current position of
// the stream is advanced by two.
//
public virtual void Write(short value)
{
_buffer[0] = (byte)value;
_buffer[1] = (byte)(value >> 8);
OutStream.Write(_buffer, 0, 2);
}
// Writes a two-byte unsigned integer to this stream. The current position
// of the stream is advanced by two.
//
//[CLSCompliant(false)]
public virtual void Write(ushort value)
{
_buffer[0] = (byte)value;
_buffer[1] = (byte)(value >> 8);
OutStream.Write(_buffer, 0, 2);
}
// Writes a four-byte signed integer to this stream. The current position
// of the stream is advanced by four.
//
public virtual void Write(int value)
{
_buffer[0] = (byte)value;
_buffer[1] = (byte)(value >> 8);
_buffer[2] = (byte)(value >> 16);
_buffer[3] = (byte)(value >> 24);
OutStream.Write(_buffer, 0, 4);
}
// Writes a four-byte unsigned integer to this stream. The current position
// of the stream is advanced by four.
//
//[CLSCompliant(false)]
public virtual void Write(uint value)
{
_buffer[0] = (byte)value;
_buffer[1] = (byte)(value >> 8);
_buffer[2] = (byte)(value >> 16);
_buffer[3] = (byte)(value >> 24);
OutStream.Write(_buffer, 0, 4);
}
// Writes an eight-byte signed integer to this stream. The current position
// of the stream is advanced by eight.
//
public virtual void Write(long value)
{
_buffer[0] = (byte)value;
_buffer[1] = (byte)(value >> 8);
_buffer[2] = (byte)(value >> 16);
_buffer[3] = (byte)(value >> 24);
_buffer[4] = (byte)(value >> 32);
_buffer[5] = (byte)(value >> 40);
_buffer[6] = (byte)(value >> 48);
_buffer[7] = (byte)(value >> 56);
OutStream.Write(_buffer, 0, 8);
}
// Writes an eight-byte unsigned integer to this stream. The current
// position of the stream is advanced by eight.
//
//[CLSCompliant(false)]
public virtual void Write(ulong value)
{
_buffer[0] = (byte)value;
_buffer[1] = (byte)(value >> 8);
_buffer[2] = (byte)(value >> 16);
_buffer[3] = (byte)(value >> 24);
_buffer[4] = (byte)(value >> 32);
_buffer[5] = (byte)(value >> 40);
_buffer[6] = (byte)(value >> 48);
_buffer[7] = (byte)(value >> 56);
OutStream.Write(_buffer, 0, 8);
}
// Writes a float to this stream. The current position of the stream is
// advanced by four.
//
public unsafe virtual void Write(float value)
{
uint TmpValue = *(uint*)&value;
_buffer[0] = (byte)TmpValue;
_buffer[1] = (byte)(TmpValue >> 8);
_buffer[2] = (byte)(TmpValue >> 16);
_buffer[3] = (byte)(TmpValue >> 24);
OutStream.Write(_buffer, 0, 4);
}
// Writes a length-prefixed string to this stream in the BinaryWriter's
// current Encoding. This method first writes the length of the string as
// a four-byte unsigned integer, and then writes that many characters
// to the stream.
//
public unsafe virtual void Write(string value)
{
if (value == null)
{
throw new ArgumentNullException("value");
}
int len = _encoding.GetByteCount(value);
Write7BitEncodedInt(len);
if (_largeByteBuffer == null)
{
_largeByteBuffer = new byte[LargeByteBufferSize];
_maxChars = LargeByteBufferSize / _encoding.GetMaxByteCount(1);
}
if (len <= LargeByteBufferSize)
{
_encoding.GetBytes(value, 0, value.Length, _largeByteBuffer, 0);
OutStream.Write(_largeByteBuffer, 0, len);
}
else
{
// Aggressively try to not allocate memory in this loop for
// runtime performance reasons. Use an Encoder to write out
// the string correctly (handling surrogates crossing buffer
// boundaries properly).
int charStart = 0;
int numLeft = value.Length;
#if DEBUG
int totalBytes = 0;
#endif
while (numLeft > 0)
{
// Figure out how many chars to process this round.
int charCount = (numLeft > _maxChars) ? _maxChars : numLeft;
int byteLen;
byteLen = _encoder.GetBytes(value.ToCharArray(), charStart, charCount, _largeByteBuffer, 0, charCount == numLeft);
#if DEBUG
totalBytes += byteLen;
Debug.Assert(totalBytes <= len && byteLen <= LargeByteBufferSize, "BinaryWriter::Write(String) - More bytes encoded than expected!");
#endif
OutStream.Write(_largeByteBuffer, 0, byteLen);
charStart += charCount;
numLeft -= charCount;
}
#if DEBUG
Debug.Assert(totalBytes == len, "BinaryWriter::Write(String) - Didn't write out all the bytes!");
#endif
}
}
protected void Write7BitEncodedInt(int value)
{
// Write out an int 7 bits at a time. The high bit of the byte,
// when on, tells reader to continue reading more bytes.
uint v = (uint)value; // support negative numbers
while (v >= 0x80)
{
Write((byte)(v | 0x80));
v >>= 7;
}
Write((byte)v);
}
}