The Labs \ Source Viewer \ SSCLI \ System.IO \ BinaryWriter

  1. // ==++==
  2. //
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. //
  14. // ==--==
  15. /*============================================================
  16. **
  17. ** Class:  BinaryWriter
  18. **
  19. ** Purpose: Provides a way to write primitives types in
  20. ** binary from a Stream, while also supporting writing Strings
  21. ** in a particular encoding.
  22. **
  23. **
  24. ===========================================================*/
  25. using System;
  26. using System.Text;
  27. namespace System.IO
  28. {
  29.     // This abstract base class represents a writer that can write
  30.     // primitives to an arbitrary stream. A subclass can override methods to
  31.     // give unique encodings.
  32.     //
  33.     [Serializable()]
  34.     [System.Runtime.InteropServices.ComVisible(true)]
  35.     public class BinaryWriter : IDisposable
  36.     {
  37.         public static readonly BinaryWriter Null = new BinaryWriter();
  38.        
  39.         protected Stream OutStream;
  40.         private byte[] _buffer;
  41.         // temp space for writing primitives to.
  42.         private Encoding _encoding;
  43.         private Encoder _encoder;
  44.         private char[] _tmpOneCharBuffer = new char[1];
  45.        
  46.         // Perf optimization stuff
  47.         private byte[] _largeByteBuffer;
  48.         // temp space for writing chars.
  49.         private int _maxChars;
  50.         // max # of chars we can put in _largeByteBuffer
  51.         // Size should be around the max number of chars/string * Encoding's max bytes/char
  52.         private const int LargeByteBufferSize = 256;
  53.        
  54.         // Protected default constructor that sets the output stream
  55.         // to a null stream (a bit bucket).
  56.         protected BinaryWriter()
  57.         {
  58.             OutStream = Stream.Null;
  59.             _buffer = new byte[16];
  60.             _encoding = new UTF8Encoding(false, true);
  61.             _encoder = _encoding.GetEncoder();
  62.         }
  63.        
  64.         public BinaryWriter(Stream output) : this(output, new UTF8Encoding(false, true))
  65.         {
  66.         }
  67.        
  68.         public BinaryWriter(Stream output, Encoding encoding)
  69.         {
  70.             if (output == null)
  71.                 throw new ArgumentNullException("output");
  72.             if (encoding == null)
  73.                 throw new ArgumentNullException("encoding");
  74.             if (!output.CanWrite)
  75.                 throw new ArgumentException(Environment.GetResourceString("Argument_StreamNotWritable"));
  76.            
  77.             OutStream = output;
  78.             _buffer = new byte[16];
  79.             _encoding = encoding;
  80.             _encoder = _encoding.GetEncoder();
  81.         }
  82.        
  83.         // Closes this writer and releases any system resources associated with the
  84.         // writer. Following a call to Close, any operations on the writer
  85.         // may raise exceptions.
  86.         public virtual void Close()
  87.         {
  88.             Dispose(true);
  89.         }
  90.        
  91.         protected virtual void Dispose(bool disposing)
  92.         {
  93.             if (disposing)
  94.                 OutStream.Close();
  95.         }
  96.        
  97.         /// <internalonly/>
  98.         void IDisposable.Dispose()
  99.         {
  100.             Dispose(true);
  101.         }
  102.        
  103. /*
  104.         * Returns the stream associate with the writer. It flushes all pending
  105.         * writes before returning. All subclasses should override Flush to
  106.         * ensure that all buffered data is sent to the stream.
  107.         */       
  108.         public virtual Stream BaseStream {
  109.             get {
  110.                 Flush();
  111.                 return OutStream;
  112.             }
  113.         }
  114.        
  115.         // Clears all buffers for this writer and causes any buffered data to be
  116.         // written to the underlying device.
  117.         public virtual void Flush()
  118.         {
  119.             OutStream.Flush();
  120.         }
  121.        
  122.         public virtual long Seek(int offset, SeekOrigin origin)
  123.         {
  124.             return OutStream.Seek(offset, origin);
  125.         }
  126.        
  127.         // Writes a boolean to this stream. A single byte is written to the stream
  128.         // with the value 0 representing false or the value 1 representing true.
  129.         //
  130.         public virtual void Write(bool value)
  131.         {
  132.             _buffer[0] = (byte)(value ? 1 : 0);
  133.             OutStream.Write(_buffer, 0, 1);
  134.         }
  135.        
  136.         // Writes a byte to this stream. The current position of the stream is
  137.         // advanced by one.
  138.         //
  139.         public virtual void Write(byte value)
  140.         {
  141.             OutStream.WriteByte(value);
  142.         }
  143.        
  144.         // Writes a signed byte to this stream. The current position of the stream
  145.         // is advanced by one.
  146.         //
  147.         [CLSCompliant(false)]
  148.         public virtual void Write(sbyte value)
  149.         {
  150.             OutStream.WriteByte((byte)value);
  151.         }
  152.        
  153.         // Writes a byte array to this stream.
  154.         //
  155.         // This default implementation calls the Write(Object, int, int)
  156.         // method to write the byte array.
  157.         //
  158.         public virtual void Write(byte[] buffer)
  159.         {
  160.             if (buffer == null)
  161.                 throw new ArgumentNullException("buffer");
  162.             OutStream.Write(buffer, 0, buffer.Length);
  163.         }
  164.        
  165.         // Writes a section of a byte array to this stream.
  166.         //
  167.         // This default implementation calls the Write(Object, int, int)
  168.         // method to write the byte array.
  169.         //
  170.         public virtual void Write(byte[] buffer, int index, int count)
  171.         {
  172.             OutStream.Write(buffer, index, count);
  173.         }
  174.        
  175.        
  176.         // Writes a character to this stream. The current position of the stream is
  177.         // advanced by two.
  178.         // Note this method cannot handle surrogates properly in UTF-8.
  179.         //
  180.         unsafe public virtual void Write(char ch)
  181.         {
  182.             if (Char.IsSurrogate(ch))
  183.                 throw new ArgumentException(Environment.GetResourceString("Arg_SurrogatesNotAllowedAsSingleChar"));
  184.            
  185.             BCLDebug.Assert(_encoding.GetMaxByteCount(1) <= 16, "_encoding.GetMaxByteCount(1) <= 16)");
  186.             int numBytes = 0;
  187.             fixed (byte* pBytes = _buffer) {
  188.                 numBytes = _encoder.GetBytes(&ch, 1, pBytes, 16, true);
  189.             }
  190.             OutStream.Write(_buffer, 0, numBytes);
  191.         }
  192.        
  193.         // Writes a character array to this stream.
  194.         //
  195.         // This default implementation calls the Write(Object, int, int)
  196.         // method to write the character array.
  197.         //
  198.         public virtual void Write(char[] chars)
  199.         {
  200.             if (chars == null)
  201.                 throw new ArgumentNullException("chars");
  202.            
  203.             byte[] bytes = _encoding.GetBytes(chars, 0, chars.Length);
  204.             OutStream.Write(bytes, 0, bytes.Length);
  205.         }
  206.        
  207.         // Writes a section of a character array to this stream.
  208.         //
  209.         // This default implementation calls the Write(Object, int, int)
  210.         // method to write the character array.
  211.         //
  212.         public virtual void Write(char[] chars, int index, int count)
  213.         {
  214.             byte[] bytes = _encoding.GetBytes(chars, index, count);
  215.             OutStream.Write(bytes, 0, bytes.Length);
  216.         }
  217.        
  218.        
  219.         // Writes a double to this stream. The current position of the stream is
  220.         // advanced by eight.
  221.         //
  222.         unsafe public virtual void Write(double value)
  223.         {
  224.             ulong TmpValue = *(ulong*)&value;
  225.             _buffer[0] = (byte)TmpValue;
  226.             _buffer[1] = (byte)(TmpValue >> 8);
  227.             _buffer[2] = (byte)(TmpValue >> 16);
  228.             _buffer[3] = (byte)(TmpValue >> 24);
  229.             _buffer[4] = (byte)(TmpValue >> 32);
  230.             _buffer[5] = (byte)(TmpValue >> 40);
  231.             _buffer[6] = (byte)(TmpValue >> 48);
  232.             _buffer[7] = (byte)(TmpValue >> 56);
  233.             OutStream.Write(_buffer, 0, 8);
  234.         }
  235.        
  236.         public virtual void Write(decimal value)
  237.         {
  238.             Decimal.GetBytes(value, _buffer);
  239.             OutStream.Write(_buffer, 0, 16);
  240.         }
  241.        
  242.         // Writes a two-byte signed integer to this stream. The current position of
  243.         // the stream is advanced by two.
  244.         //
  245.         public virtual void Write(short value)
  246.         {
  247.             _buffer[0] = (byte)value;
  248.             _buffer[1] = (byte)(value >> 8);
  249.             OutStream.Write(_buffer, 0, 2);
  250.         }
  251.        
  252.         // Writes a two-byte unsigned integer to this stream. The current position
  253.         // of the stream is advanced by two.
  254.         //
  255.         [CLSCompliant(false)]
  256.         public virtual void Write(ushort value)
  257.         {
  258.             _buffer[0] = (byte)value;
  259.             _buffer[1] = (byte)(value >> 8);
  260.             OutStream.Write(_buffer, 0, 2);
  261.         }
  262.        
  263.         // Writes a four-byte signed integer to this stream. The current position
  264.         // of the stream is advanced by four.
  265.         //
  266.         public virtual void Write(int value)
  267.         {
  268.             _buffer[0] = (byte)value;
  269.             _buffer[1] = (byte)(value >> 8);
  270.             _buffer[2] = (byte)(value >> 16);
  271.             _buffer[3] = (byte)(value >> 24);
  272.             OutStream.Write(_buffer, 0, 4);
  273.         }
  274.        
  275.         // Writes a four-byte unsigned integer to this stream. The current position
  276.         // of the stream is advanced by four.
  277.         //
  278.         [CLSCompliant(false)]
  279.         public virtual void Write(uint value)
  280.         {
  281.             _buffer[0] = (byte)value;
  282.             _buffer[1] = (byte)(value >> 8);
  283.             _buffer[2] = (byte)(value >> 16);
  284.             _buffer[3] = (byte)(value >> 24);
  285.             OutStream.Write(_buffer, 0, 4);
  286.         }
  287.        
  288.         // Writes an eight-byte signed integer to this stream. The current position
  289.         // of the stream is advanced by eight.
  290.         //
  291.         public virtual void Write(long value)
  292.         {
  293.             _buffer[0] = (byte)value;
  294.             _buffer[1] = (byte)(value >> 8);
  295.             _buffer[2] = (byte)(value >> 16);
  296.             _buffer[3] = (byte)(value >> 24);
  297.             _buffer[4] = (byte)(value >> 32);
  298.             _buffer[5] = (byte)(value >> 40);
  299.             _buffer[6] = (byte)(value >> 48);
  300.             _buffer[7] = (byte)(value >> 56);
  301.             OutStream.Write(_buffer, 0, 8);
  302.         }
  303.        
  304.         // Writes an eight-byte unsigned integer to this stream. The current
  305.         // position of the stream is advanced by eight.
  306.         //
  307.         [CLSCompliant(false)]
  308.         public virtual void Write(ulong value)
  309.         {
  310.             _buffer[0] = (byte)value;
  311.             _buffer[1] = (byte)(value >> 8);
  312.             _buffer[2] = (byte)(value >> 16);
  313.             _buffer[3] = (byte)(value >> 24);
  314.             _buffer[4] = (byte)(value >> 32);
  315.             _buffer[5] = (byte)(value >> 40);
  316.             _buffer[6] = (byte)(value >> 48);
  317.             _buffer[7] = (byte)(value >> 56);
  318.             OutStream.Write(_buffer, 0, 8);
  319.         }
  320.        
  321.         // Writes a float to this stream. The current position of the stream is
  322.         // advanced by four.
  323.         //
  324.         unsafe public virtual void Write(float value)
  325.         {
  326.             uint TmpValue = *(uint*)&value;
  327.             _buffer[0] = (byte)TmpValue;
  328.             _buffer[1] = (byte)(TmpValue >> 8);
  329.             _buffer[2] = (byte)(TmpValue >> 16);
  330.             _buffer[3] = (byte)(TmpValue >> 24);
  331.             OutStream.Write(_buffer, 0, 4);
  332.         }
  333.        
  334.        
  335.         // Writes a length-prefixed string to this stream in the BinaryWriter's
  336.         // current Encoding. This method first writes the length of the string as
  337.         // a four-byte unsigned integer, and then writes that many characters
  338.         // to the stream.
  339.         //
  340.         unsafe public virtual void Write(string value)
  341.         {
  342.             if (value == null)
  343.                 throw new ArgumentNullException("value");
  344.            
  345.             int len = _encoding.GetByteCount(value);
  346.             Write7BitEncodedInt(len);
  347.            
  348.             if (_largeByteBuffer == null) {
  349.                 _largeByteBuffer = new byte[LargeByteBufferSize];
  350.                 _maxChars = LargeByteBufferSize / _encoding.GetMaxByteCount(1);
  351.             }
  352.            
  353.             if (len <= LargeByteBufferSize) {
  354.                 //BCLDebug.Assert(len == _encoding.GetBytes(chars, 0, chars.Length, _largeByteBuffer, 0), "encoding's GetByteCount & GetBytes gave different answers! encoding type: "+_encoding.GetType().Name);
  355.                 _encoding.GetBytes(value, 0, value.Length, _largeByteBuffer, 0);
  356.                 OutStream.Write(_largeByteBuffer, 0, len);
  357.             }
  358.             else {
  359.                 // Aggressively try to not allocate memory in this loop for
  360.                 // runtime performance reasons. Use an Encoder to write out
  361.                 // the string correctly (handling surrogates crossing buffer
  362.                 // boundaries properly).
  363.                 int charStart = 0;
  364.                 int numLeft = value.Length;
  365.                 #if _DEBUG
  366.                 int totalBytes = 0;
  367.                 #endif
  368.                 while (numLeft > 0) {
  369.                     // Figure out how many chars to process this round.
  370.                     int charCount = (numLeft > _maxChars) ? _maxChars : numLeft;
  371.                     int byteLen;
  372.                     fixed (char* pChars = value) {
  373.                         fixed (byte* pBytes = _largeByteBuffer) {
  374.                             byteLen = _encoder.GetBytes(pChars + charStart, charCount, pBytes, LargeByteBufferSize, charCount == numLeft);
  375.                         }
  376.                     }
  377.                     #if _DEBUG
  378.                     totalBytes += byteLen;
  379.                     BCLDebug.Assert(totalBytes <= len && byteLen <= LargeByteBufferSize, "BinaryWriter::Write(String) - More bytes encoded than expected!");
  380.                     #endif
  381.                     OutStream.Write(_largeByteBuffer, 0, byteLen);
  382.                     charStart += charCount;
  383.                     numLeft -= charCount;
  384.                 }
  385.                 #if _DEBUG
  386.                 BCLDebug.Assert(totalBytes == len, "BinaryWriter::Write(String) - Didn't write out all the bytes!");
  387.                 #endif
  388.             }
  389.         }
  390.        
  391.         protected void Write7BitEncodedInt(int value)
  392.         {
  393.             // Write out an int 7 bits at a time. The high bit of the byte,
  394.             // when on, tells reader to continue reading more bytes.
  395.             uint v = (uint)value;
  396.             // support negative numbers
  397.             while (v >= 128) {
  398.                 Write((byte)(v | 128));
  399.                 v >>= 7;
  400.             }
  401.             Write((byte)v);
  402.         }
  403.     }
  404. }

Developer Fusion