public void AddFile(string root, string filename, Reference reference)
{
string fullFilename = Path.Combine(root, filename);
using (FileStream fileStreamIn = new FileStream(fullFilename, FileMode.Open, FileAccess.Read, FileShare.Read, Settings.FileStreamBufferSize, true)) {
stats.Status = "Compressing " + filename;
stats.Progress = 0;
BufferName = filename;
BufferNameSuffix = 0;
BufferNameForceAppendSuffix = false;
SHA1CryptoServiceProvider sha1Provider = new SHA1CryptoServiceProvider();
// Store
List<int> hashIndices = new List<int>();
long offset = 0;
foreach (Block block in Splitter.Split(fileStreamIn, sha1Provider, false)) {
if (stats.Canceled) return;
Hash hash = Hash.Compute(block);
HashSource referenceHash;
string referenceHashPath;
int hashIndex;
if (hashesLookup.TryGetValue(hash, out hashIndex)) {
// Internal reference
stats.SavedByInternalDelta += block.Length;
BufferNameForceAppendSuffix = true;
} else if (reference != null && reference.TryFindHash(hash, out referenceHash, out referenceHashPath)) {
// Reference to existing archive
stats.SavedByExternalDelta += block.Length;
BufferNameForceAppendSuffix = true;
// Copy the hash to local array
referenceHash.Path = this.AddString(referenceHashPath);
hashes.Add(referenceHash);
hashIndex = hashes.Count - 1;
hashesLookup[hash] = hashIndex;
} else {
// Store the data locally
hashIndex = WriteToBuffer(hash, block);
hashesLookup[hash] = hashIndex;
}
hashIndices.Add(hashIndex);
offset += block.Length;
stats.Progress = (float)offset / (float)fileStreamIn.Length;
};
if (offset != fileStreamIn.Length)
throw new Exception("Internal consistency error");
FlushBuffer(true);
FileInfo fileInfo = new FileInfo(fullFilename);
File file = new File() {
Name = filename,
Size = fileInfo.Length,
Hash = sha1Provider.Hash,
Created = fileInfo.CreationTime,
Modified = fileInfo.LastWriteTime,
Attributes = fileInfo.Attributes & ~Settings.IgnoreAttributes,
HashIndices = hashIndices
};
files.Add(file);
}
}