Modules/Filesystem/FileContainer.vb
2018-11-09 10:47:59 +01:00

197 lines
7.1 KiB
VB.net

Imports System.IO
Imports System.Runtime.Serialization.Formatters.Binary
Public Class FileContainer
Private _files As List(Of FileEntry)
Private _crypto As Encryption
Private _compression As Compression
Private _formatter As BinaryFormatter
<Serializable>
Public Class FileEntry
Public FileId As String
Public Contents As Byte()
End Class
''' <summary>
''' Gibt eine Auflistung der Dateien in Container zurück.
''' </summary>
''' <returns>Eine Liste von Objekten der Klasse FileContainer.FileEntry</returns>
Public ReadOnly Property Files As List(Of FileEntry)
Get
Return _files
End Get
End Property
''' <summary>
''' Erstellt eine Representation eines Datei Containers, der mit dem angegebenen Passwort geschützt ist.
''' Ist für das speichern von neuen Containern und für das laden vorhandener Container nötig.
''' </summary>
''' <param name="password">Das Passwort, mit dem der Container ver- und entschlüsselt wird</param>
''' <example>
''' Dim password = "meinpasswort"
''' Dim container = new FileContainer(password)
''' </example>
Public Sub New(password As String)
_crypto = New Encryption(password)
_compression = New Compression()
_formatter = New BinaryFormatter()
_files = New List(Of FileEntry)
End Sub
''' <summary>
''' Speichert einen Datei Container am angegebenen Pfad.
''' Davor werden die Dateien in Files komprimiert und dann verschlüsselt.
''' </summary>
''' <param name="path">Der Pfad mit Dateiname, unter dem der Container abgelegt wird.</param>
''' <see cref="Files"/>
''' <example>
''' container.AddFile("datei1.txt")
''' container.AddFile("datei2.pdf")
''' container.Save("container.enc")
''' </example>
Public Sub Save(path As String)
' 1. Serialize
Dim bFiles As Byte() = Serialize(_files)
' 2. Compress
Dim bFilesCompressed As Byte() = _compression.Compress(bFiles)
' 3. Encrypt
Dim bFilesEncrypted As Byte() = _crypto.Encrypt(bFilesCompressed)
BytesToFile(bFilesEncrypted, path)
End Sub
''' <summary>
''' Speichert einen Datei Container am angegebenen Pfad.
''' Davor werden die Dateien in Files komprimiert und dann verschlüsselt.
''' </summary>
''' <param name="path">Der Pfad mit Dateiname, unter dem der Container abgelegt wird.</param>
''' <example>
''' Public Async Sub foobar()
''' ...
''' container.AddFile("datei1.txt")
''' container.AddFile("datei2.pdf")
''' await container.SaveAsync("container.enc")
''' ...
''' End Sub
''' </example>
Public Async Function SaveAsync(path As String) As Task
' 1. Serialize
Dim bFiles As Byte() = Serialize(_files)
' 2. Compress
Dim bFilesCompressed As Byte() = Await _compression.CompressAsync(bFiles)
'Dim bFilesCompressed = bFiles
' 3. Encrypt
Dim bFilesEncrypted As Byte() = Await _crypto.EncryptAsync(bFilesCompressed)
BytesToFileAsync(bFilesEncrypted, path)
End Function
''' <summary>
''' Lädt einen Datei Container aus dem angegebenen Pfad.
''' Anschließend werden die enthaltenen Dateien entschlüsselt, dekomprimiert und in Files abgelegt.
''' </summary>
''' <param name="path">Der Pfad mit Dateiname, von dem der Container geladen wird.</param>
''' <see cref="Files"/>
''' <example>
''' container.Load("container.enc")
''' Dim files As List(Of FileContainer.FileEntry) = container.Files
''' </example>
Public Sub Load(path As String)
Dim bFilesEncrypted As Byte() = FileToBytes(path)
' 1. Decrypt
Dim bFiles As Byte() = _crypto.Decrypt(bFilesEncrypted)
' 2. Decompress
Dim bFilesDecompressed As Byte() = _compression.Decompress(bFiles)
' 3. Deserialize
_files = Deserialize(bFilesDecompressed)
End Sub
''' <summary>
''' Lädt einen Datei Container aus dem angegebenen Pfad.
''' Anschließend werden die enthaltenen Dateien entschlüsselt, dekomprimiert und in Files abgelegt.
''' </summary>
''' <param name="path">Der Pfad mit Dateiname, von dem der Container geladen wird.</param>
''' <example>
''' Public Async Sub foobar()
''' ...
''' await container.LoadAsync("container.enc")
''' Dim files As List(Of FileContainer.FileEntry) = container.Files
''' ...
''' End Sub
''' </example>
Public Async Function LoadAsync(path As String) As Task
Dim bFilesEncrypted As Byte() = Await FileToBytesAsync(path)
' 1. Decrypt
Dim bFiles As Byte() = Await _crypto.DecryptAsync(bFilesEncrypted)
' 2. Decompress
Dim bFilesDecompressed As Byte() = Await _compression.DecompressAsync(bFiles)
'Dim bFilesDecompressed = bFiles
' 3. Deserialize
_files = Deserialize(bFilesDecompressed)
End Function
''' <summary>
''' Fügt einem Datei Container eine neue Datei hinzu
''' </summary>
''' <param name="filePath">Der Pfad zur Datei, die im Container gespeichert werden soll</param>
''' <exception cref="FileNotFoundException" />
Public Sub AddFile(filePath As String)
Dim fi As New FileInfo(filePath)
Dim fe As New FileEntry()
If fi.Exists = False Then
Throw New FileNotFoundException($"{filePath} is not a valid path.")
End If
fe.Contents = IO.File.ReadAllBytes(filePath)
fe.FileId = Guid.NewGuid().ToString()
_files.Add(fe)
End Sub
Public Function GetFile(fileId As String) As FileEntry
Return _files.Where(Function(f) f.FileId = fileId).FirstOrDefault()
End Function
Private Function Serialize(list As List(Of FileEntry)) As Byte()
Using ms As New MemoryStream
_formatter.Serialize(ms, list)
Return ms.ToArray()
End Using
End Function
Private Function Deserialize(data As Byte()) As List(Of FileEntry)
Using ms As New MemoryStream(data)
Dim list = TryCast(_formatter.Deserialize(ms), List(Of FileEntry))
Return list
End Using
End Function
Private Sub BytesToFile(data As Byte(), filePath As String)
IO.File.WriteAllBytes(filePath, data)
End Sub
Private Function FileToBytes(filePath As String) As Byte()
Return IO.File.ReadAllBytes(filePath)
End Function
Private Async Function FileToBytesAsync(filePath As String) As Task(Of Byte())
Using file = New FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, True)
Dim buff As Byte() = New Byte(file.Length - 1) {}
Await file.ReadAsync(buff, 0, file.Length)
file.Close()
Return buff
End Using
End Function
Private Async Sub BytesToFileAsync(data As Byte(), filePath As String)
Using sourceStream As New FileStream(filePath, FileMode.Append, FileAccess.Write, FileShare.None, bufferSize:=4096, useAsync:=True)
Await sourceStream.WriteAsync(data, 0, data.Length)
End Using
End Sub
End Class