using System;
using System.IO;
using System.Collections;
namespace Be.Windows.Forms
{
///
/// Byte provider for (big) files.
///
public class FileByteProvider : IByteProvider, IDisposable
{
#region WriteCollection class
///
/// Represents the write buffer class
///
class WriteCollection : DictionaryBase
{
///
/// Gets or sets a byte in the collection
///
public byte this[long index]
{
get { return (byte)this.Dictionary[index]; }
set { Dictionary[index] = value; }
}
///
/// Adds a byte into the collection
///
/// the index of the byte
/// the value of the byte
public void Add(long index, byte value)
{ Dictionary.Add(index, value); }
///
/// Determines if a byte with the given index exists.
///
/// the index of the byte
/// true, if the is in the collection
public bool Contains(long index)
{ return Dictionary.Contains(index); }
}
#endregion
///
/// Occurs, when the write buffer contains new changes.
///
public event EventHandler Changed;
///
/// Contains all changes
///
WriteCollection _writes = new WriteCollection();
///
/// Contains the file name.
///
string _fileName;
///
/// Contains the file stream.
///
FileStream _fileStream;
///
/// Read-only access.
///
bool _readOnly;
///
/// Initializes a new instance of the FileByteProvider class.
///
///
public FileByteProvider(string fileName)
{
_fileName = fileName;
try
{
// try to open in write mode
_fileStream = File.Open(fileName, FileMode.Open, FileAccess.ReadWrite, FileShare.Read);
}
catch
{
// write mode failed, try to open in read-only and fileshare friendly mode.
try
{
_fileStream = File.Open(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
_readOnly = true;
}
catch
{
throw;
}
}
}
///
/// Terminates the instance of the FileByteProvider class.
///
~FileByteProvider()
{
Dispose();
}
///
/// Raises the Changed event.
///
/// Never used.
void OnChanged(EventArgs e)
{
if(Changed != null)
Changed(this, e);
}
///
/// Gets the name of the file the byte provider is using.
///
public string FileName
{
get { return _fileName; }
}
///
/// Returns a value if there are some changes.
///
/// true, if there are some changes
public bool HasChanges()
{
return (_writes.Count > 0);
}
///
/// Updates the file with all changes the write buffer contains.
///
public void ApplyChanges()
{
if (this._readOnly)
{
throw new Exception("File is in read-only mode.");
}
if(!HasChanges())
return;
IDictionaryEnumerator en = _writes.GetEnumerator();
while(en.MoveNext())
{
long index = (long)en.Key;
byte value = (byte)en.Value;
if(_fileStream.Position != index)
_fileStream.Position = index;
_fileStream.Write(new byte[] { value }, 0, 1);
}
_writes.Clear();
}
///
/// Clears the write buffer and reject all changes made.
///
public void RejectChanges()
{
_writes.Clear();
}
#region IByteProvider Members
///
/// Never used.
///
public event EventHandler LengthChanged;
///
/// Never Used
///
/// Event Args
protected virtual void OnLengthChanged (EventArgs e)
{
if (LengthChanged != null)
LengthChanged(this, e);
}
///
/// Reads a byte from the file.
///
/// the index of the byte to read
/// the byte
public byte ReadByte(long index)
{
if(_writes.Contains(index))
return _writes[index];
if(_fileStream.Position != index)
_fileStream.Position = index;
byte res = (byte)_fileStream.ReadByte();
return res;
}
///
/// Gets the length of the file.
///
public long Length
{
get
{
return _fileStream.Length;
}
}
///
/// Writes a byte into write buffer
///
public void WriteByte(long index, byte value)
{
if(_writes.Contains(index))
_writes[index] = value;
else
_writes.Add(index, value);
OnChanged(EventArgs.Empty);
}
///
/// Not supported
///
public void DeleteBytes(long index, long length)
{
throw new NotSupportedException("FileByteProvider.DeleteBytes");
}
///
/// Not supported
///
public void InsertBytes(long index, byte[] bs)
{
throw new NotSupportedException("FileByteProvider.InsertBytes");
}
///
/// Returns true
///
public bool SupportsWriteByte()
{
return !_readOnly;
}
///
/// Returns false
///
public bool SupportsInsertBytes()
{
return false;
}
///
/// Returns false
///
public bool SupportsDeleteBytes()
{
return false;
}
#endregion
#region IDisposable Members
///
/// Releases the file handle used by the FileByteProvider.
///
public void Dispose()
{
if(_fileStream != null)
{
_fileName = null;
_fileStream.Close();
_fileStream = null;
}
GC.SuppressFinalize(this);
}
#endregion
}
}