// // BwgBurn - CD-R/CD-RW/DVD-R/DVD-RW burning program for Windows XP // // Copyright (C) 2006 by Jack W. Griffin (butchg@comcast.net) // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License // for more details. // // You should have received a copy of the GNU General Public License along // with this program; if not, write to the // // Free Software Foundation, Inc., // 59 Temple Place, Suite 330, // Boston, MA 02111-1307 USA // using System; using System.Collections.Generic; using System.Text; using System.IO ; using System.Runtime.InteropServices; using System.Diagnostics; namespace Bwg.Scsi { /// /// A stream that pushes the output data through the buffer pool to feed /// the CD/DVD burner. /// public class WriteBufferStream: Stream { #region private data members /// /// The current length of the stream in bytes /// private long m_length ; /// /// The buffer pool, used to get buffers to write into and used to send /// buffers to the device. /// private WriteBufferPool m_pool; /// /// The current buffer we are writing into /// private WriteBuffer m_buffer; /// /// The size of the sectors that will be sent to the device, in bytes /// private int m_sector_size; /// /// The number of sectors that fit into a single write buffer /// private int m_sector_count; /// /// The index into the current write buffer /// private int m_index; /// /// If true, we are closing /// private bool m_closing; /// /// The logical block address for the stream data /// private long m_lba; #endregion #region constructors /// /// This is a stream class that writes the data to the write buffer pool to be sent /// down to the CD/DVD device. /// /// the buffer pool to get pages from and send data to /// the size of the sectors to buffer /// the logical block address for the first block from this stream public WriteBufferStream(WriteBufferPool pool, int sector_size, long lba) { m_length = 0; m_pool = pool; m_buffer = null; m_index = 0; m_sector_size = sector_size; m_sector_count = m_pool.PageSize / m_sector_size; m_closing = false; m_lba = lba; } #endregion #region public properties /// /// /// public override bool CanRead { get { return false; } } /// /// /// public override bool CanSeek { get { return false; } } /// /// /// public override bool CanWrite { get { return true ; } } /// /// /// public override long Length { get { return m_length ; } } /// /// /// public override long Position { get { return m_length; } set { throw new Exception("The method or operation is not implemented."); } } #endregion #region public methods /// /// This method flushes any existing data to the device. /// public override void Flush() { if (m_buffer != null) { // // In general using flush, except when closing the device can be very // dangerous. This method catches those cases where the result sent to // the device would be incorrect and asserts accordingly. Basically we // always send data down to the device in sectors. When we flush we send // down whatever data is left in the buffer. If we are closing, this has // the effect of rounding the last bit of data to a sector boundary. If // we are not closing, it can have the effect of inserting data in the // middle of the data stream. Flusing only works correctly if we are sitting // on the boundary of a sector. Therefore, if this assert has fired it means // we are not closing and not sitting on the boundary of a sector. // Debug.Assert(m_closing || (m_index % m_sector_size) == 0); m_buffer.DataSize = m_index / m_sector_size; if ((m_index % m_sector_size) != 0) m_buffer.DataSize++; m_buffer.SectorSize = m_sector_size; m_buffer.SourceString = "WriteBufferStream, Flush method"; m_buffer.LogicalBlockAddress = m_lba; m_lba = long.MaxValue; m_pool.SendBufferToDevice(m_buffer); } } /// /// /// /// /// /// public override long Seek(long offset, SeekOrigin origin) { throw new Exception("The method or operation is not implemented."); } /// /// /// /// /// /// /// public override int Read(byte[] buffer, int offset, int count) { throw new Exception("The method or operation is not implemented."); } /// /// /// /// /// /// public override void Write(byte[] buffer, int offset, int count) { while (count > 0) { if (m_buffer == null) { m_buffer = m_pool.GetFreeBuffer(); m_index = 0; } // // Write up to the end of this buffer // int remaining = m_sector_count * m_sector_size - m_index; if (remaining > count) remaining = count; IntPtr dest = new IntPtr(m_buffer.BufferPtr.ToInt32() + m_index); Marshal.Copy(buffer, offset, dest, remaining); m_index += remaining; m_length += remaining; count -= remaining ; offset += remaining ; if (m_index == m_sector_count * m_sector_size) { m_buffer.DataSize = m_index / m_sector_size; m_buffer.SectorSize = m_sector_size; m_buffer.LogicalBlockAddress = m_lba; m_buffer.SourceString = "WriteBufferStream, Write method"; m_lba = long.MaxValue; m_pool.SendBufferToDevice(m_buffer); m_buffer = null; } } } /// /// /// /// public override void SetLength(long value) { throw new Exception("The method or operation is not implemented."); } /// /// /// public override void Close() { m_closing = true; Flush(); base.Close(); } #endregion } }