Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / wpf / src / Framework / System / Windows / Markup / XamlStream.cs / 1 / XamlStream.cs
/****************************************************************************\ * * File: XamlStream.cs * * Purpose: Contains the Reader/Writer stream implementation for * Doing async parsing on a separate thread. * * Todo: Make Sure Reader/Writer calls are on proper Threads * Todo: Add logic to stop the Writer if buffer >> than * What is being loaded into the Tree. * Todo: Investigate if worthwhile keeping a cache of Buffers * That get re-used instead of allocating one each time. * Todo: Review if ReadByte needs to be optimized * Todo: Need End Of File Markers so reader doesn't have to rely on * getting the BamlEndRecord. * // History: // 6/06/02: rogerg Created // 5/27/03: peterost Ported to wcp * * Copyright (C) 2002 by Microsoft Corporation. All rights reserved. * \***************************************************************************/ using System; using System.Xml; using System.IO; using System.Windows; using System.Collections; using System.ComponentModel; using System.Diagnostics; using System.Reflection; using System.Threading; using MS.Utility; #if PBTCOMPILER namespace MS.Internal.Markup #else namespace System.Windows.Markup #endif { ////// Main class for setting up Reader and Writer streams as well as /// keeping common data and any synchronization work. /// /// Writer is allowed write and seek back to any position in the file /// until it calls UpdateReaderLength(position). The position passed in is /// an absolute position in the file. After making this call the Writer is /// only allowed to seek and write past this position. /// /// The Reader only sees the part of the file that the Writer says is ready /// to read. Initially the length of the Reader stream is zero. When the Writer /// calls UpdateReaderLength(position)the length of the Reader stream is set /// to that position. The Reader calls ReaderDoneWithFileUpToPosition(position) to indicate /// it no longer needs the file up to and including that position. After this call /// it is an error for the Reader to try read bits before the position. /// internal class ReadWriteStreamManager { #region Constructors #if PBTCOMPILER // The compiler only needs the class definition, and none of the implementation. private ReadWriteStreamManager() #else internal ReadWriteStreamManager() #endif { ReaderFirstBufferPosition = 0; WriterFirstBufferPosition = 0; ReaderBufferArrayList = new ArrayList(); WriterBufferArrayList = new ArrayList(); _writerStream = new WriterStream(this); _readerStream = new ReaderStream(this); _bufferLock = new ReaderWriterLock(); } #endregion Constructors #region WriterCallbacks ////// Writes the counts of bytes into the stream. /// /// input buffer /// starting offset into the buffer /// number of bytes to write internal void Write(byte[] buffer, int offset, int count) { int bufferOffset; int bufferIndex; #if DEBUG Debug.Assert(!WriteComplete,"Write called after close"); #endif Debug.Assert(null != buffer,"Null buffer past to the Writer"); // if nothing to write then just return. if (0 == count) { return; } byte[] writeBuffer = GetBufferFromFilePosition( WritePosition,false /*writer*/, out bufferOffset, out bufferIndex); Debug.Assert(null != writeBuffer,"Null writeBuffer returned"); // see how many bits fit into this buffer. int availableBytesInBuffer = BufferSize - bufferOffset; int leftOverBytes = 0; int bufferWriteCount = 0; // check if ther is enough room in the write buffer to meet the // request or if there will be leftOverBytes. if (count > availableBytesInBuffer) { bufferWriteCount = availableBytesInBuffer; leftOverBytes = count - availableBytesInBuffer; } else { leftOverBytes = 0; bufferWriteCount = count; } Debug.Assert(0 < bufferWriteCount,"Not writing any bytes to the buffer"); // now loop through writing out all or the number of bits that can fit in the buffer. for (int loopCount = 0; loopCount < bufferWriteCount; loopCount++) { Debug.Assert(bufferOffset < BufferSize,"Trying to Read past bufer"); writeBuffer[bufferOffset++] = buffer[offset++]; } // update the writePosition WritePosition += bufferWriteCount; // check if need to update length of the file that the writer sees. if (WritePosition > WriteLength) { WriteLength = WritePosition; } // if we have any leftOver Bytes call Write Again. if (leftOverBytes > 0) { Write(buffer,offset,leftOverBytes); } } ////// Adjust the Writer's Seek Pointer. /// Writer is not allowed to Seek before where the ReaderLength or /// Seek past the writeLength. /// /// seek offset /// specifies how to interpret the seeek offset ///internal long WriterSeek(long offset, SeekOrigin loc) { switch(loc) { case SeekOrigin.Begin: WritePosition = (int) offset; break; case SeekOrigin.Current: WritePosition = (int) (WritePosition + offset); break; case SeekOrigin.End: throw new NotSupportedException(SR.Get(SRID.ParserWriterNoSeekEnd)); default: throw new ArgumentException(SR.Get(SRID.ParserWriterUnknownOrigin)); } if( (!( WritePosition <= WriteLength )) || (!( WritePosition >= ReadLength )) ) { throw new ArgumentOutOfRangeException( "offset" ); } return WritePosition; } /// /// Called by the Writer to indicate its okay for the reader to see /// the file up to and including the position. Once the Writer calls /// this it cannot go back and change the content. /// /// Absolute position in the stream internal void UpdateReaderLength(long position) { if(!(ReadLength <= position)) { throw new ArgumentOutOfRangeException( "position" ); } #if DEBUG Debug.Assert(!WriteComplete,"UpdateReaderLength called after close"); #endif ReadLength = position; if(!(ReadLength <= WriteLength)) { throw new ArgumentOutOfRangeException( "position" ); } // safe for them to check and remove unused buffers. CheckIfCanRemoveFromArrayList(position,WriterBufferArrayList, ref _writerFirstBufferPosition); } ////// Closes the Writer Stream /// internal void WriterClose() { #if DEBUG _writeComplete = true; #endif } #endregion WriterCallbacks #region ReaderCallbacks ////// Reads the specified number of bytes into the buffer /// /// buffer to add the bytes /// zero base starting offset /// number of bytes to read ///internal int Read(byte[] buffer, int offset, int count) { if(!(count + ReadPosition <= ReadLength)) { throw new ArgumentOutOfRangeException( "count" ); } int bufferOffset; int bufferIndex; byte[] readBuffer = GetBufferFromFilePosition( ReadPosition,true /*reader*/, out bufferOffset, out bufferIndex); Debug.Assert(bufferOffset < BufferSize,"Calculated bufferOffset is greater than buffer"); // see how many bytes we can read from this buffer. int availableBytesInBuffer = BufferSize - bufferOffset; int leftOverBytes = 0; int bufferReadCount = 0; // check if ther is enough room in the write buffer to meet the // request or if there will be leftOverBytes. if (count > availableBytesInBuffer) { bufferReadCount = availableBytesInBuffer; leftOverBytes = count - availableBytesInBuffer; } else { leftOverBytes = 0; bufferReadCount = count; } Debug.Assert(0 < bufferReadCount,"Not reading any bytes to the buffer"); for (int loopCount = 0; loopCount < bufferReadCount; loopCount++) { // make sure not going over the buffer. Debug.Assert(bufferOffset < BufferSize,"Trying ot read past buffer"); buffer[offset++] = readBuffer[bufferOffset++]; } // update the read position ReadPosition += bufferReadCount; if (leftOverBytes > 0) { Read(buffer,offset,(int) leftOverBytes); } return count; } /// /// Called to Read a Byte from the file. for now we allocate a byte /// and call the standard Read method. /// ///internal int ReadByte() { // todo, make a better implementation. byte[] buffer = new byte[1]; // uses Read to validate if reading past the end of the file. Read(buffer,0,1); return (int) buffer[0]; } /// /// Adjusts the Reader Seek position. /// /// offset for the seek /// defines relative offset ///internal long ReaderSeek(long offset, SeekOrigin loc) { switch(loc) { case SeekOrigin.Begin: ReadPosition = (int) offset; break; case SeekOrigin.Current: ReadPosition = (int) (ReadPosition + offset); break; case SeekOrigin.End: throw new NotSupportedException(SR.Get(SRID.ParserWriterNoSeekEnd)); default: throw new ArgumentException(SR.Get(SRID.ParserWriterUnknownOrigin)); } // validate if at a good readPosition. if((!(ReadPosition >= ReaderFirstBufferPosition)) || (!(ReadPosition < ReadLength))) { throw new ArgumentOutOfRangeException( "offset" ); } return ReadPosition; } /// /// called by Reader to tell us it is done with everything /// up to the given position. Once making this call the /// Reader can no long reader at and before the position. /// /// internal void ReaderDoneWithFileUpToPosition(long position) { // call CheckIfCanRemove to update the readers BufferPositions // and do any cleanup. CheckIfCanRemoveFromArrayList(position,ReaderBufferArrayList, ref _readerFirstBufferPosition); } #endregion ReaderCallbacks #region PrivateMethods ////// Given a position in the Stream returns the buffer and /// start offset position in the buffer /// byte[] GetBufferFromFilePosition(long position,bool reader, out int bufferOffset,out int bufferIndex) { byte[] buffer = null; // get bufferArray and firstBuffer position based // on if being called by the reader or the writer. ArrayList bufferArray; // arraylist of buffers long firstBufferPosition; // absolute file position of first buffer in the arrayList // Ensure that while buffer and buffer position are stable while calculating // buffer offsets and retrieving the buffer. The tokenizer thread can call // CheckIfCanRemoveFromArrayList, which uses this same lock when modifying the // writer buffer. _bufferLock.AcquireWriterLock(-1); if (reader) { bufferArray = ReaderBufferArrayList; firstBufferPosition = ReaderFirstBufferPosition; } else { bufferArray = WriterBufferArrayList; firstBufferPosition = WriterFirstBufferPosition; } // calc get the bufferIndex bufferIndex = (int) ((position - firstBufferPosition)/BufferSize); // calc the byte offset in the buffer for the position bufferOffset = (int) ((position - firstBufferPosition) - (bufferIndex*BufferSize)); Debug.Assert(bufferOffset < BufferSize,"Calculated bufferOffset is greater than buffer"); // check if we need to allocate a new buffer. if (bufferArray.Count <= bufferIndex) { Debug.Assert(bufferArray.Count == bufferIndex,"Need to allocate more than one buffer"); Debug.Assert(false == reader,"Allocating a buffer on Read"); buffer = new byte[BufferSize]; // add to both the reader and writer ArrayLists. ReaderBufferArrayList.Add(buffer); WriterBufferArrayList.Add(buffer); } else { // just use the buffer that is there. buffer = bufferArray[bufferIndex] as byte[]; } _bufferLock.ReleaseWriterLock(); return buffer; } ////// helper function called by to check is any memory buffers /// can be safely removed. /// /// Absolute File Position /// ArrayList containing the Memory /// If any arrays are cleaned up returns the /// updated position that the first array in the buffer starts at void CheckIfCanRemoveFromArrayList(long position,ArrayList arrayList,ref long firstBufferPosition) { // see if there are any buffers we can get rid of. int bufferIndex = (int) ((position - firstBufferPosition)/BufferSize); if (bufferIndex > 0) { // we can safely remove all previous buffers from the ArrayList. int numBuffersToRemove = bufferIndex; // Ensure that while modifying the buffer position and buffer list that // another thread can't get partially updated information while // calling GetBufferFromFilePosition(). _bufferLock.AcquireWriterLock(-1); // update buffer position offset for number of buffers to be // removed. firstBufferPosition += numBuffersToRemove*BufferSize; arrayList.RemoveRange(0,bufferIndex); _bufferLock.ReleaseWriterLock(); } } #endregion PrivateMethods #region Properties ////// WriterStream instance /// internal WriterStream WriterStream { get { return _writerStream; } } ////// ReaderStream instance /// internal ReaderStream ReaderStream { get { return _readerStream; } } ////// Current position inthe Reader stream /// internal long ReadPosition { get { return _readPosition; } set { _readPosition = value; } } ////// Length of the Reader stream /// internal long ReadLength { get { return _readLength; } set { _readLength = value; } } ////// Current position in the writer stream /// internal long WritePosition { get { return _writePosition ; } set { _writePosition = value; } } ////// current length of the writer stream /// internal long WriteLength { get { return _writeLength ; } set { _writeLength = value; } } ////// Constant Buffer size to be used for all allocated buffers /// int BufferSize { get { return _bufferSize; } } ////// File Position that the first buffer in the Readers array of buffer starts at /// long ReaderFirstBufferPosition { get { return _readerFirstBufferPosition ; } set { _readerFirstBufferPosition = value; } } ////// File Position that the first buffer in the Writers array of buffer starts at /// long WriterFirstBufferPosition { get { return _writerFirstBufferPosition ; } set { _writerFirstBufferPosition = value; } } ////// ArrayList containing all the buffers used by the Reader /// ArrayList ReaderBufferArrayList { get { return _readerBufferArrayList ; } set { _readerBufferArrayList = value; } } ////// ArrayList of all the buffers used by the Writer. /// ArrayList WriterBufferArrayList { get { return _writerBufferArrayList ; } set { _writerBufferArrayList = value; } } #if DEBUG ////// Set when all bytes have been written /// internal bool WriteComplete { get { return _writeComplete; } } #endif #endregion Properties #region Data long _readPosition; long _readLength; long _writePosition; long _writeLength; ReaderWriterLock _bufferLock; WriterStream _writerStream; ReaderStream _readerStream; long _readerFirstBufferPosition; long _writerFirstBufferPosition; ArrayList _readerBufferArrayList; ArrayList _writerBufferArrayList; #if DEBUG bool _writeComplete; #endif // size of each allocated buffer. private const int _bufferSize = 4096; #endregion Data } ////// Writer Stream class. /// This is the Stream implementation the Writer sees. /// internal class WriterStream : Stream { #region Constructor ////// Constructor /// /// StreamManager that the writer stream should use internal WriterStream(ReadWriteStreamManager streamManager) { _streamManager = streamManager; } #endregion Constructor #region overrides ////// Override of Stream.CanRead /// public override bool CanRead { get { return false; } } ////// Override of Stream.CanSeek /// public override bool CanSeek { get { return true; } } ////// Override of Stream.CanWrite /// public override bool CanWrite { get { return true; } } ////// Override of Stream.Close /// public override void Close() { StreamManager.WriterClose(); } ////// Override of Stream.Flush /// public override void Flush() { return; // nothing to Flush } ////// Override of Stream.Length /// public override long Length { get { return StreamManager.WriteLength; } } ////// Override of Stream.Position /// public override long Position { get { return -1; } set { throw new NotSupportedException(); } } ////// Override of Stream.Read /// public override int Read(byte[] buffer, int offset, int count) { throw new NotSupportedException(); } ////// Override of Stream.ReadByte /// public override int ReadByte() { throw new NotSupportedException(); } ////// Override of Stream.Seek /// public override long Seek(long offset, SeekOrigin loc) { return StreamManager.WriterSeek(offset,loc); } ////// Override of Stream.SetLength /// public override void SetLength(long value) { throw new NotSupportedException(); } ////// Override of Stream.Write /// public override void Write(byte[] buffer, int offset, int count) { StreamManager.Write(buffer,offset,count); } #endregion overrides #region Methods ////// Called by the writer to say its okay to let the reader see what /// it has written up to the position. /// /// Absolute position inthe file internal void UpdateReaderLength(long position) { StreamManager.UpdateReaderLength(position); } #endregion Methods #region Properties ////// StreamManager for the writer stream /// ReadWriteStreamManager StreamManager { get { return _streamManager; } } #endregion Properties #region Data ReadWriteStreamManager _streamManager; #endregion Data } ////// Reader Stream class /// This is the Stream implementation the Writer sees. /// internal class ReaderStream : Stream { #region Constructor internal ReaderStream(ReadWriteStreamManager streamManager) { _streamManager = streamManager; } #endregion Constructor #region overrides ////// Override of Stream.CanRead /// public override bool CanRead { get { return true; } } ////// Override of Stream.CanSeek /// public override bool CanSeek { get { return true; } } ////// Override of Stream.CanWrite /// public override bool CanWrite { get { return false; } } ////// Override of Stream.Close /// public override void Close() { Debug.Assert(false,"Close called on ReaderStream"); } ////// Override of Stream.Flush /// public override void Flush() { Debug.Assert(false,"Flush called on ReaderStream"); } ////// Override of Stream.Length /// public override long Length { get { return StreamManager.ReadLength; } } ////// Override of Stream.Position /// public override long Position { get { return StreamManager.ReadPosition; } set { StreamManager.ReaderSeek(value,SeekOrigin.Begin); } } ////// Override of Stream.Read /// public override int Read(byte[] buffer, int offset, int count) { return StreamManager.Read(buffer,offset,count); } ////// Override of Stream.ReadByte /// public override int ReadByte() { return StreamManager.ReadByte(); } ////// Override of Stream.Seek /// public override long Seek(long offset, SeekOrigin loc) { return StreamManager.ReaderSeek(offset,loc); } ////// Override of Stream.SetLength /// public override void SetLength(long value) { throw new NotSupportedException(); } ////// Override of Stream.Write /// public override void Write(byte[] buffer, int offset, int count) { throw new NotSupportedException(); } #endregion Overrides #region Methods ////// Called by the reader to indicate all bytes up to and /// including the position are no longer needed /// After making this call the reader cannot go back and /// read this data /// /// internal void ReaderDoneWithFileUpToPosition(long position) { StreamManager.ReaderDoneWithFileUpToPosition(position); } #if DEBUG internal bool IsWriteComplete { get { return StreamManager.WriteComplete; } } #endif #endregion Methods #region Properties ////// StreamManager that this class should use /// ReadWriteStreamManager StreamManager { get { return _streamManager; } } #endregion Properties #region Data ReadWriteStreamManager _streamManager; #endregion Data } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved. /****************************************************************************\ * * File: XamlStream.cs * * Purpose: Contains the Reader/Writer stream implementation for * Doing async parsing on a separate thread. * * Todo: Make Sure Reader/Writer calls are on proper Threads * Todo: Add logic to stop the Writer if buffer >> than * What is being loaded into the Tree. * Todo: Investigate if worthwhile keeping a cache of Buffers * That get re-used instead of allocating one each time. * Todo: Review if ReadByte needs to be optimized * Todo: Need End Of File Markers so reader doesn't have to rely on * getting the BamlEndRecord. * // History: // 6/06/02: rogerg Created // 5/27/03: peterost Ported to wcp * * Copyright (C) 2002 by Microsoft Corporation. All rights reserved. * \***************************************************************************/ using System; using System.Xml; using System.IO; using System.Windows; using System.Collections; using System.ComponentModel; using System.Diagnostics; using System.Reflection; using System.Threading; using MS.Utility; #if PBTCOMPILER namespace MS.Internal.Markup #else namespace System.Windows.Markup #endif { ////// Main class for setting up Reader and Writer streams as well as /// keeping common data and any synchronization work. /// /// Writer is allowed write and seek back to any position in the file /// until it calls UpdateReaderLength(position). The position passed in is /// an absolute position in the file. After making this call the Writer is /// only allowed to seek and write past this position. /// /// The Reader only sees the part of the file that the Writer says is ready /// to read. Initially the length of the Reader stream is zero. When the Writer /// calls UpdateReaderLength(position)the length of the Reader stream is set /// to that position. The Reader calls ReaderDoneWithFileUpToPosition(position) to indicate /// it no longer needs the file up to and including that position. After this call /// it is an error for the Reader to try read bits before the position. /// internal class ReadWriteStreamManager { #region Constructors #if PBTCOMPILER // The compiler only needs the class definition, and none of the implementation. private ReadWriteStreamManager() #else internal ReadWriteStreamManager() #endif { ReaderFirstBufferPosition = 0; WriterFirstBufferPosition = 0; ReaderBufferArrayList = new ArrayList(); WriterBufferArrayList = new ArrayList(); _writerStream = new WriterStream(this); _readerStream = new ReaderStream(this); _bufferLock = new ReaderWriterLock(); } #endregion Constructors #region WriterCallbacks ////// Writes the counts of bytes into the stream. /// /// input buffer /// starting offset into the buffer /// number of bytes to write internal void Write(byte[] buffer, int offset, int count) { int bufferOffset; int bufferIndex; #if DEBUG Debug.Assert(!WriteComplete,"Write called after close"); #endif Debug.Assert(null != buffer,"Null buffer past to the Writer"); // if nothing to write then just return. if (0 == count) { return; } byte[] writeBuffer = GetBufferFromFilePosition( WritePosition,false /*writer*/, out bufferOffset, out bufferIndex); Debug.Assert(null != writeBuffer,"Null writeBuffer returned"); // see how many bits fit into this buffer. int availableBytesInBuffer = BufferSize - bufferOffset; int leftOverBytes = 0; int bufferWriteCount = 0; // check if ther is enough room in the write buffer to meet the // request or if there will be leftOverBytes. if (count > availableBytesInBuffer) { bufferWriteCount = availableBytesInBuffer; leftOverBytes = count - availableBytesInBuffer; } else { leftOverBytes = 0; bufferWriteCount = count; } Debug.Assert(0 < bufferWriteCount,"Not writing any bytes to the buffer"); // now loop through writing out all or the number of bits that can fit in the buffer. for (int loopCount = 0; loopCount < bufferWriteCount; loopCount++) { Debug.Assert(bufferOffset < BufferSize,"Trying to Read past bufer"); writeBuffer[bufferOffset++] = buffer[offset++]; } // update the writePosition WritePosition += bufferWriteCount; // check if need to update length of the file that the writer sees. if (WritePosition > WriteLength) { WriteLength = WritePosition; } // if we have any leftOver Bytes call Write Again. if (leftOverBytes > 0) { Write(buffer,offset,leftOverBytes); } } ////// Adjust the Writer's Seek Pointer. /// Writer is not allowed to Seek before where the ReaderLength or /// Seek past the writeLength. /// /// seek offset /// specifies how to interpret the seeek offset ///internal long WriterSeek(long offset, SeekOrigin loc) { switch(loc) { case SeekOrigin.Begin: WritePosition = (int) offset; break; case SeekOrigin.Current: WritePosition = (int) (WritePosition + offset); break; case SeekOrigin.End: throw new NotSupportedException(SR.Get(SRID.ParserWriterNoSeekEnd)); default: throw new ArgumentException(SR.Get(SRID.ParserWriterUnknownOrigin)); } if( (!( WritePosition <= WriteLength )) || (!( WritePosition >= ReadLength )) ) { throw new ArgumentOutOfRangeException( "offset" ); } return WritePosition; } /// /// Called by the Writer to indicate its okay for the reader to see /// the file up to and including the position. Once the Writer calls /// this it cannot go back and change the content. /// /// Absolute position in the stream internal void UpdateReaderLength(long position) { if(!(ReadLength <= position)) { throw new ArgumentOutOfRangeException( "position" ); } #if DEBUG Debug.Assert(!WriteComplete,"UpdateReaderLength called after close"); #endif ReadLength = position; if(!(ReadLength <= WriteLength)) { throw new ArgumentOutOfRangeException( "position" ); } // safe for them to check and remove unused buffers. CheckIfCanRemoveFromArrayList(position,WriterBufferArrayList, ref _writerFirstBufferPosition); } ////// Closes the Writer Stream /// internal void WriterClose() { #if DEBUG _writeComplete = true; #endif } #endregion WriterCallbacks #region ReaderCallbacks ////// Reads the specified number of bytes into the buffer /// /// buffer to add the bytes /// zero base starting offset /// number of bytes to read ///internal int Read(byte[] buffer, int offset, int count) { if(!(count + ReadPosition <= ReadLength)) { throw new ArgumentOutOfRangeException( "count" ); } int bufferOffset; int bufferIndex; byte[] readBuffer = GetBufferFromFilePosition( ReadPosition,true /*reader*/, out bufferOffset, out bufferIndex); Debug.Assert(bufferOffset < BufferSize,"Calculated bufferOffset is greater than buffer"); // see how many bytes we can read from this buffer. int availableBytesInBuffer = BufferSize - bufferOffset; int leftOverBytes = 0; int bufferReadCount = 0; // check if ther is enough room in the write buffer to meet the // request or if there will be leftOverBytes. if (count > availableBytesInBuffer) { bufferReadCount = availableBytesInBuffer; leftOverBytes = count - availableBytesInBuffer; } else { leftOverBytes = 0; bufferReadCount = count; } Debug.Assert(0 < bufferReadCount,"Not reading any bytes to the buffer"); for (int loopCount = 0; loopCount < bufferReadCount; loopCount++) { // make sure not going over the buffer. Debug.Assert(bufferOffset < BufferSize,"Trying ot read past buffer"); buffer[offset++] = readBuffer[bufferOffset++]; } // update the read position ReadPosition += bufferReadCount; if (leftOverBytes > 0) { Read(buffer,offset,(int) leftOverBytes); } return count; } /// /// Called to Read a Byte from the file. for now we allocate a byte /// and call the standard Read method. /// ///internal int ReadByte() { // todo, make a better implementation. byte[] buffer = new byte[1]; // uses Read to validate if reading past the end of the file. Read(buffer,0,1); return (int) buffer[0]; } /// /// Adjusts the Reader Seek position. /// /// offset for the seek /// defines relative offset ///internal long ReaderSeek(long offset, SeekOrigin loc) { switch(loc) { case SeekOrigin.Begin: ReadPosition = (int) offset; break; case SeekOrigin.Current: ReadPosition = (int) (ReadPosition + offset); break; case SeekOrigin.End: throw new NotSupportedException(SR.Get(SRID.ParserWriterNoSeekEnd)); default: throw new ArgumentException(SR.Get(SRID.ParserWriterUnknownOrigin)); } // validate if at a good readPosition. if((!(ReadPosition >= ReaderFirstBufferPosition)) || (!(ReadPosition < ReadLength))) { throw new ArgumentOutOfRangeException( "offset" ); } return ReadPosition; } /// /// called by Reader to tell us it is done with everything /// up to the given position. Once making this call the /// Reader can no long reader at and before the position. /// /// internal void ReaderDoneWithFileUpToPosition(long position) { // call CheckIfCanRemove to update the readers BufferPositions // and do any cleanup. CheckIfCanRemoveFromArrayList(position,ReaderBufferArrayList, ref _readerFirstBufferPosition); } #endregion ReaderCallbacks #region PrivateMethods ////// Given a position in the Stream returns the buffer and /// start offset position in the buffer /// byte[] GetBufferFromFilePosition(long position,bool reader, out int bufferOffset,out int bufferIndex) { byte[] buffer = null; // get bufferArray and firstBuffer position based // on if being called by the reader or the writer. ArrayList bufferArray; // arraylist of buffers long firstBufferPosition; // absolute file position of first buffer in the arrayList // Ensure that while buffer and buffer position are stable while calculating // buffer offsets and retrieving the buffer. The tokenizer thread can call // CheckIfCanRemoveFromArrayList, which uses this same lock when modifying the // writer buffer. _bufferLock.AcquireWriterLock(-1); if (reader) { bufferArray = ReaderBufferArrayList; firstBufferPosition = ReaderFirstBufferPosition; } else { bufferArray = WriterBufferArrayList; firstBufferPosition = WriterFirstBufferPosition; } // calc get the bufferIndex bufferIndex = (int) ((position - firstBufferPosition)/BufferSize); // calc the byte offset in the buffer for the position bufferOffset = (int) ((position - firstBufferPosition) - (bufferIndex*BufferSize)); Debug.Assert(bufferOffset < BufferSize,"Calculated bufferOffset is greater than buffer"); // check if we need to allocate a new buffer. if (bufferArray.Count <= bufferIndex) { Debug.Assert(bufferArray.Count == bufferIndex,"Need to allocate more than one buffer"); Debug.Assert(false == reader,"Allocating a buffer on Read"); buffer = new byte[BufferSize]; // add to both the reader and writer ArrayLists. ReaderBufferArrayList.Add(buffer); WriterBufferArrayList.Add(buffer); } else { // just use the buffer that is there. buffer = bufferArray[bufferIndex] as byte[]; } _bufferLock.ReleaseWriterLock(); return buffer; } ////// helper function called by to check is any memory buffers /// can be safely removed. /// /// Absolute File Position /// ArrayList containing the Memory /// If any arrays are cleaned up returns the /// updated position that the first array in the buffer starts at void CheckIfCanRemoveFromArrayList(long position,ArrayList arrayList,ref long firstBufferPosition) { // see if there are any buffers we can get rid of. int bufferIndex = (int) ((position - firstBufferPosition)/BufferSize); if (bufferIndex > 0) { // we can safely remove all previous buffers from the ArrayList. int numBuffersToRemove = bufferIndex; // Ensure that while modifying the buffer position and buffer list that // another thread can't get partially updated information while // calling GetBufferFromFilePosition(). _bufferLock.AcquireWriterLock(-1); // update buffer position offset for number of buffers to be // removed. firstBufferPosition += numBuffersToRemove*BufferSize; arrayList.RemoveRange(0,bufferIndex); _bufferLock.ReleaseWriterLock(); } } #endregion PrivateMethods #region Properties ////// WriterStream instance /// internal WriterStream WriterStream { get { return _writerStream; } } ////// ReaderStream instance /// internal ReaderStream ReaderStream { get { return _readerStream; } } ////// Current position inthe Reader stream /// internal long ReadPosition { get { return _readPosition; } set { _readPosition = value; } } ////// Length of the Reader stream /// internal long ReadLength { get { return _readLength; } set { _readLength = value; } } ////// Current position in the writer stream /// internal long WritePosition { get { return _writePosition ; } set { _writePosition = value; } } ////// current length of the writer stream /// internal long WriteLength { get { return _writeLength ; } set { _writeLength = value; } } ////// Constant Buffer size to be used for all allocated buffers /// int BufferSize { get { return _bufferSize; } } ////// File Position that the first buffer in the Readers array of buffer starts at /// long ReaderFirstBufferPosition { get { return _readerFirstBufferPosition ; } set { _readerFirstBufferPosition = value; } } ////// File Position that the first buffer in the Writers array of buffer starts at /// long WriterFirstBufferPosition { get { return _writerFirstBufferPosition ; } set { _writerFirstBufferPosition = value; } } ////// ArrayList containing all the buffers used by the Reader /// ArrayList ReaderBufferArrayList { get { return _readerBufferArrayList ; } set { _readerBufferArrayList = value; } } ////// ArrayList of all the buffers used by the Writer. /// ArrayList WriterBufferArrayList { get { return _writerBufferArrayList ; } set { _writerBufferArrayList = value; } } #if DEBUG ////// Set when all bytes have been written /// internal bool WriteComplete { get { return _writeComplete; } } #endif #endregion Properties #region Data long _readPosition; long _readLength; long _writePosition; long _writeLength; ReaderWriterLock _bufferLock; WriterStream _writerStream; ReaderStream _readerStream; long _readerFirstBufferPosition; long _writerFirstBufferPosition; ArrayList _readerBufferArrayList; ArrayList _writerBufferArrayList; #if DEBUG bool _writeComplete; #endif // size of each allocated buffer. private const int _bufferSize = 4096; #endregion Data } ////// Writer Stream class. /// This is the Stream implementation the Writer sees. /// internal class WriterStream : Stream { #region Constructor ////// Constructor /// /// StreamManager that the writer stream should use internal WriterStream(ReadWriteStreamManager streamManager) { _streamManager = streamManager; } #endregion Constructor #region overrides ////// Override of Stream.CanRead /// public override bool CanRead { get { return false; } } ////// Override of Stream.CanSeek /// public override bool CanSeek { get { return true; } } ////// Override of Stream.CanWrite /// public override bool CanWrite { get { return true; } } ////// Override of Stream.Close /// public override void Close() { StreamManager.WriterClose(); } ////// Override of Stream.Flush /// public override void Flush() { return; // nothing to Flush } ////// Override of Stream.Length /// public override long Length { get { return StreamManager.WriteLength; } } ////// Override of Stream.Position /// public override long Position { get { return -1; } set { throw new NotSupportedException(); } } ////// Override of Stream.Read /// public override int Read(byte[] buffer, int offset, int count) { throw new NotSupportedException(); } ////// Override of Stream.ReadByte /// public override int ReadByte() { throw new NotSupportedException(); } ////// Override of Stream.Seek /// public override long Seek(long offset, SeekOrigin loc) { return StreamManager.WriterSeek(offset,loc); } ////// Override of Stream.SetLength /// public override void SetLength(long value) { throw new NotSupportedException(); } ////// Override of Stream.Write /// public override void Write(byte[] buffer, int offset, int count) { StreamManager.Write(buffer,offset,count); } #endregion overrides #region Methods ////// Called by the writer to say its okay to let the reader see what /// it has written up to the position. /// /// Absolute position inthe file internal void UpdateReaderLength(long position) { StreamManager.UpdateReaderLength(position); } #endregion Methods #region Properties ////// StreamManager for the writer stream /// ReadWriteStreamManager StreamManager { get { return _streamManager; } } #endregion Properties #region Data ReadWriteStreamManager _streamManager; #endregion Data } ////// Reader Stream class /// This is the Stream implementation the Writer sees. /// internal class ReaderStream : Stream { #region Constructor internal ReaderStream(ReadWriteStreamManager streamManager) { _streamManager = streamManager; } #endregion Constructor #region overrides ////// Override of Stream.CanRead /// public override bool CanRead { get { return true; } } ////// Override of Stream.CanSeek /// public override bool CanSeek { get { return true; } } ////// Override of Stream.CanWrite /// public override bool CanWrite { get { return false; } } ////// Override of Stream.Close /// public override void Close() { Debug.Assert(false,"Close called on ReaderStream"); } ////// Override of Stream.Flush /// public override void Flush() { Debug.Assert(false,"Flush called on ReaderStream"); } ////// Override of Stream.Length /// public override long Length { get { return StreamManager.ReadLength; } } ////// Override of Stream.Position /// public override long Position { get { return StreamManager.ReadPosition; } set { StreamManager.ReaderSeek(value,SeekOrigin.Begin); } } ////// Override of Stream.Read /// public override int Read(byte[] buffer, int offset, int count) { return StreamManager.Read(buffer,offset,count); } ////// Override of Stream.ReadByte /// public override int ReadByte() { return StreamManager.ReadByte(); } ////// Override of Stream.Seek /// public override long Seek(long offset, SeekOrigin loc) { return StreamManager.ReaderSeek(offset,loc); } ////// Override of Stream.SetLength /// public override void SetLength(long value) { throw new NotSupportedException(); } ////// Override of Stream.Write /// public override void Write(byte[] buffer, int offset, int count) { throw new NotSupportedException(); } #endregion Overrides #region Methods ////// Called by the reader to indicate all bytes up to and /// including the position are no longer needed /// After making this call the reader cannot go back and /// read this data /// /// internal void ReaderDoneWithFileUpToPosition(long position) { StreamManager.ReaderDoneWithFileUpToPosition(position); } #if DEBUG internal bool IsWriteComplete { get { return StreamManager.WriteComplete; } } #endif #endregion Methods #region Properties ////// StreamManager that this class should use /// ReadWriteStreamManager StreamManager { get { return _streamManager; } } #endregion Properties #region Data ReadWriteStreamManager _streamManager; #endregion Data } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- VariableQuery.cs
- TreeView.cs
- WebPartConnectionsCancelVerb.cs
- SpellerInterop.cs
- QueryableDataSourceView.cs
- DeclaredTypeElementCollection.cs
- Enlistment.cs
- BitmapEffectState.cs
- sqlmetadatafactory.cs
- AnnotationStore.cs
- X509Certificate2.cs
- DataGridRowClipboardEventArgs.cs
- HWStack.cs
- autovalidator.cs
- SmiEventSink_DeferedProcessing.cs
- MenuBase.cs
- SecurityResources.cs
- ChannelManager.cs
- ClusterUtils.cs
- HttpWriter.cs
- SystemSounds.cs
- EdmProviderManifest.cs
- ContextMenu.cs
- XmlSchemaObjectTable.cs
- ConfigXmlCDataSection.cs
- PriorityRange.cs
- DBDataPermissionAttribute.cs
- RuleInfoComparer.cs
- NeutralResourcesLanguageAttribute.cs
- ComplexLine.cs
- FunctionDetailsReader.cs
- NamespaceMapping.cs
- NumberFunctions.cs
- StorageInfo.cs
- PKCS1MaskGenerationMethod.cs
- CommandConverter.cs
- DictionarySectionHandler.cs
- Merger.cs
- InternalBufferOverflowException.cs
- SmtpException.cs
- ByteStack.cs
- SplitterPanel.cs
- UIElement.cs
- ReadOnlyPermissionSet.cs
- ComplusTypeValidator.cs
- Directory.cs
- oledbmetadatacolumnnames.cs
- ProgressiveCrcCalculatingStream.cs
- RelatedCurrencyManager.cs
- CallbackValidatorAttribute.cs
- DynamicResourceExtension.cs
- EventRouteFactory.cs
- IImplicitResourceProvider.cs
- nulltextnavigator.cs
- BitmapPalette.cs
- Geometry.cs
- SecurityElement.cs
- ApplyImportsAction.cs
- BindingOperations.cs
- Version.cs
- CircleHotSpot.cs
- DiagnosticTrace.cs
- Int32CAMarshaler.cs
- MimeTypePropertyAttribute.cs
- BitmapPalettes.cs
- sqlstateclientmanager.cs
- QualifiedId.cs
- XmlSerializerVersionAttribute.cs
- AnchoredBlock.cs
- Ray3DHitTestResult.cs
- DataGridViewRow.cs
- BreakRecordTable.cs
- StdValidatorsAndConverters.cs
- CriticalFinalizerObject.cs
- X509ChainElement.cs
- DataControlLinkButton.cs
- XmlILOptimizerVisitor.cs
- SerializationInfo.cs
- PowerModeChangedEventArgs.cs
- Point3DCollectionConverter.cs
- CopyEncoder.cs
- ListBoxAutomationPeer.cs
- HelloOperation11AsyncResult.cs
- MimePart.cs
- Hashtable.cs
- ShaderEffect.cs
- TimelineGroup.cs
- DockEditor.cs
- VScrollBar.cs
- SafeSecurityHandles.cs
- SqlNamer.cs
- NavigationWindowAutomationPeer.cs
- SafeArrayTypeMismatchException.cs
- DoubleAnimationClockResource.cs
- WebPartZoneCollection.cs
- EdmComplexPropertyAttribute.cs
- IsolatedStorage.cs
- DataGridViewSortCompareEventArgs.cs
- ColumnBinding.cs
- OdbcConnection.cs