// Decompiled with JetBrains decompiler // Type: System.Windows.Forms.DynamicFileByteProvider // Assembly: FiestaShark, Version=2.3.0.0, Culture=neutral, PublicKeyToken=null // MVID: 12469781-3753-4869-9C1A-117F1862B52C // Assembly location: E:\Fiesta\Emus\DragonFiesta\Tools\FiestaShark-Farbod\FiestaShark.exe using System.IO; namespace System.Windows.Forms { public sealed class DynamicFileByteProvider : IByteProvider, IDisposable { private const int COPY_BLOCK_SIZE = 4096; private string _fileName; private FileStream _fileStream; private DataMap _dataMap; private long _totalLength; private bool _readOnly; public DynamicFileByteProvider(string fileName) : this(fileName, false) { } public DynamicFileByteProvider(string fileName, bool readOnly) { this._fileName = fileName; this._fileStream = readOnly ? File.Open(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite) : File.Open(fileName, FileMode.Open, FileAccess.ReadWrite, FileShare.Read); this._readOnly = readOnly; this.ReInitialize(); } public event EventHandler LengthChanged; public event EventHandler Changed; public byte ReadByte(long index) { long blockOffset; DataBlock dataBlock = this.GetDataBlock(index, out blockOffset); return dataBlock is FileDataBlock fileDataBlock ? this.ReadByteFromFile(fileDataBlock.FileOffset + index - blockOffset) : ((MemoryDataBlock) dataBlock).Data[index - blockOffset]; } public void WriteByte(long index, byte value) { try { long blockOffset; DataBlock dataBlock = this.GetDataBlock(index, out blockOffset); if (dataBlock is MemoryDataBlock memoryDataBlock) { memoryDataBlock.Data[index - blockOffset] = value; } else { FileDataBlock fileDataBlock1 = (FileDataBlock) dataBlock; if (blockOffset == index && dataBlock.PreviousBlock != null && dataBlock.PreviousBlock is MemoryDataBlock previousBlock) { previousBlock.AddByteToEnd(value); fileDataBlock1.RemoveBytesFromStart(1L); if (fileDataBlock1.Length != 0L) return; this._dataMap.Remove((DataBlock) fileDataBlock1); } else if (blockOffset + fileDataBlock1.Length - 1L == index && dataBlock.NextBlock != null && dataBlock.NextBlock is MemoryDataBlock nextBlock) { nextBlock.AddByteToStart(value); fileDataBlock1.RemoveBytesFromEnd(1L); if (fileDataBlock1.Length != 0L) return; this._dataMap.Remove((DataBlock) fileDataBlock1); } else { FileDataBlock fileDataBlock2 = (FileDataBlock) null; if (index > blockOffset) fileDataBlock2 = new FileDataBlock(fileDataBlock1.FileOffset, index - blockOffset); FileDataBlock fileDataBlock3 = (FileDataBlock) null; if (index < blockOffset + fileDataBlock1.Length - 1L) fileDataBlock3 = new FileDataBlock(fileDataBlock1.FileOffset + index - blockOffset + 1L, fileDataBlock1.Length - (index - blockOffset + 1L)); DataBlock block = this._dataMap.Replace(dataBlock, (DataBlock) new MemoryDataBlock(value)); if (fileDataBlock2 != null) this._dataMap.AddBefore(block, (DataBlock) fileDataBlock2); if (fileDataBlock3 == null) return; this._dataMap.AddAfter(block, (DataBlock) fileDataBlock3); } } } finally { this.OnChanged(EventArgs.Empty); } } public void InsertBytes(long index, byte[] bs) { try { long blockOffset; DataBlock dataBlock = this.GetDataBlock(index, out blockOffset); if (dataBlock is MemoryDataBlock memoryDataBlock) { memoryDataBlock.InsertBytes(index - blockOffset, bs); } else { FileDataBlock fileDataBlock1 = (FileDataBlock) dataBlock; if (blockOffset == index && dataBlock.PreviousBlock != null && dataBlock.PreviousBlock is MemoryDataBlock previousBlock) { previousBlock.InsertBytes(previousBlock.Length, bs); } else { FileDataBlock fileDataBlock2 = (FileDataBlock) null; if (index > blockOffset) fileDataBlock2 = new FileDataBlock(fileDataBlock1.FileOffset, index - blockOffset); FileDataBlock fileDataBlock3 = (FileDataBlock) null; if (index < blockOffset + fileDataBlock1.Length) fileDataBlock3 = new FileDataBlock(fileDataBlock1.FileOffset + index - blockOffset, fileDataBlock1.Length - (index - blockOffset)); DataBlock block = this._dataMap.Replace(dataBlock, (DataBlock) new MemoryDataBlock(bs)); if (fileDataBlock2 != null) this._dataMap.AddBefore(block, (DataBlock) fileDataBlock2); if (fileDataBlock3 == null) return; this._dataMap.AddAfter(block, (DataBlock) fileDataBlock3); } } } finally { this._totalLength += (long) bs.Length; this.OnLengthChanged(EventArgs.Empty); this.OnChanged(EventArgs.Empty); } } public void DeleteBytes(long index, long length) { try { long val1 = length; long blockOffset; DataBlock block = this.GetDataBlock(index, out blockOffset); while (val1 > 0L) { long length1 = block.Length; DataBlock nextBlock = block.NextBlock; long count = Math.Min(val1, length1 - (index - blockOffset)); block.RemoveBytes(index - blockOffset, count); if (block.Length == 0L) { this._dataMap.Remove(block); if (this._dataMap.FirstBlock == null) this._dataMap.AddFirst((DataBlock) new MemoryDataBlock(new byte[0])); } val1 -= count; blockOffset += block.Length; block = val1 > 0L ? nextBlock : (DataBlock) null; } } finally { this._totalLength -= length; this.OnLengthChanged(EventArgs.Empty); this.OnChanged(EventArgs.Empty); } } public long Length { get { return this._totalLength; } } public bool HasChanges() { if (this._readOnly) return false; if (this._totalLength != this._fileStream.Length) return true; long num = 0; for (DataBlock dataBlock = this._dataMap.FirstBlock; dataBlock != null; dataBlock = dataBlock.NextBlock) { if (!(dataBlock is FileDataBlock fileDataBlock) || fileDataBlock.FileOffset != num) return true; num += fileDataBlock.Length; } return num != this._fileStream.Length; } public void ApplyChanges() { if (this._readOnly) throw new OperationCanceledException("File is in read-only mode"); if (this._totalLength > this._fileStream.Length) this._fileStream.SetLength(this._totalLength); long dataOffset = 0; for (DataBlock dataBlock = this._dataMap.FirstBlock; dataBlock != null; dataBlock = dataBlock.NextBlock) { if (dataBlock is FileDataBlock fileBlock && fileBlock.FileOffset != dataOffset) this.MoveFileBlock(fileBlock, dataOffset); dataOffset += dataBlock.Length; } long num = 0; for (DataBlock dataBlock = this._dataMap.FirstBlock; dataBlock != null; dataBlock = dataBlock.NextBlock) { if (dataBlock is MemoryDataBlock memoryDataBlock) { this._fileStream.Position = num; for (int offset = 0; (long) offset < memoryDataBlock.Length; offset += 4096) this._fileStream.Write(memoryDataBlock.Data, offset, (int) Math.Min(4096L, memoryDataBlock.Length - (long) offset)); } num += dataBlock.Length; } this._fileStream.SetLength(this._totalLength); this.ReInitialize(); } public bool SupportsWriteByte() { return !this._readOnly; } public bool SupportsInsertBytes() { return !this._readOnly; } public bool SupportsDeleteBytes() { return !this._readOnly; } ~DynamicFileByteProvider() { this.Dispose(); } public void Dispose() { if (this._fileStream != null) { this._fileStream.Close(); this._fileStream = (FileStream) null; } this._fileName = (string) null; this._dataMap = (DataMap) null; GC.SuppressFinalize((object) this); } public bool ReadOnly { get { return this._readOnly; } set { this._readOnly = value; } } private void OnLengthChanged(EventArgs e) { if (this.LengthChanged == null) return; this.LengthChanged((object) this, e); } private void OnChanged(EventArgs e) { if (this.Changed == null) return; this.Changed((object) this, e); } private DataBlock GetDataBlock(long findOffset, out long blockOffset) { if (findOffset < 0L || findOffset > this._totalLength) throw new ArgumentOutOfRangeException("index"); blockOffset = 0L; for (DataBlock dataBlock = this._dataMap.FirstBlock; dataBlock != null; dataBlock = dataBlock.NextBlock) { if (blockOffset <= findOffset && blockOffset + dataBlock.Length > findOffset || dataBlock.NextBlock == null) return dataBlock; blockOffset += dataBlock.Length; } return (DataBlock) null; } private FileDataBlock GetNextFileDataBlock( DataBlock block, long dataOffset, out long nextDataOffset) { nextDataOffset = dataOffset + block.Length; for (block = block.NextBlock; block != null; block = block.NextBlock) { if (block is FileDataBlock fileDataBlock) return fileDataBlock; nextDataOffset += block.Length; } return (FileDataBlock) null; } private byte ReadByteFromFile(long fileOffset) { if (this._fileStream.Position != fileOffset) this._fileStream.Position = fileOffset; return (byte) this._fileStream.ReadByte(); } private void MoveFileBlock(FileDataBlock fileBlock, long dataOffset) { long nextDataOffset; FileDataBlock nextFileDataBlock = this.GetNextFileDataBlock((DataBlock) fileBlock, dataOffset, out nextDataOffset); if (nextFileDataBlock != null && dataOffset + fileBlock.Length > nextFileDataBlock.FileOffset) this.MoveFileBlock(nextFileDataBlock, nextDataOffset); if (fileBlock.FileOffset > dataOffset) { byte[] buffer = new byte[4096]; for (long index = 0; index < fileBlock.Length; index += (long) buffer.Length) { long num = fileBlock.FileOffset + index; int count = (int) Math.Min((long) buffer.Length, fileBlock.Length - index); this._fileStream.Position = num; this._fileStream.Read(buffer, 0, count); this._fileStream.Position = dataOffset + index; this._fileStream.Write(buffer, 0, count); } } else { byte[] buffer = new byte[4096]; for (long index = 0; index < fileBlock.Length; index += (long) buffer.Length) { int count = (int) Math.Min((long) buffer.Length, fileBlock.Length - index); this._fileStream.Position = fileBlock.FileOffset + fileBlock.Length - index - (long) count; this._fileStream.Read(buffer, 0, count); this._fileStream.Position = dataOffset + fileBlock.Length - index - (long) count; this._fileStream.Write(buffer, 0, count); } } fileBlock.SetFileOffset(dataOffset); } private void ReInitialize() { this._dataMap = new DataMap(); this._dataMap.AddFirst((DataBlock) new FileDataBlock(0L, this._fileStream.Length)); this._totalLength = this._fileStream.Length; } } }