|
Antwort |
Registriert seit: 8. Jan 2007 472 Beiträge |
#1
Auch die zweite mORMot Vorstellung hat als Ausgangspunkt diese Frage im Forum. Die erstellte Beispiel-Anwendung kann als Startpunkt eigener Erkundungen dienen. Ziel ist es, so viel Funktionalität wie möglich mit nur wenigen Zeilen Quelltext zu präsentieren. Es geht hier um Konzepte, nicht um eine fertige Copy-Paste Lösung. Für das Beispiel wird mORMot2 verwendet.
Im Anhang befindet sich der Sourcecode und das ausführbare Programm. Disclaimer: Der Sourcecode ist weder getestet noch optimiert. Er sollte mit Delphi ab Version 10.2 funktionieren. Die Benutzung der zur Verfügung gestellten Materialien erfolgt auf eigene Gefahr. Die erstellte Klasse TImageResourceFile verwaltet Bilder und verwendet als Speicher eine ZIP-Datei. Die Einträge können optional AES verschlüsselt abgelegt werden. Im zweiten Teil wird die Anbindung einer Fortschrittsanzeige mit Hilfe eines Mediators vorgestellt. Zum Ende zeige ich einige praktische Funktionen und die Ergebnisse einer kleinen Write-Speed-Challenge zwischen Delphi- und mORMot-ZIP, mit einem für mich unerwarteten Ergebnis. Das Interface der Klasse TImageResourceFile ist sehr einfach gehalten und umfasst nur wenige Funktionen:
Delphi-Quellcode:
Mit dem Beispiel Quelltext bekommt man:
TImageResourceFile = class(TObject)
private FPassword: RawUtf8; FFileName: TFileName; FIsWritable: Boolean; protected function LoadStream(pmStream: TCustomMemoryStream; const pmcResName: TFileName; const pmcPassword: RawUtf8): Boolean; procedure SaveStream(pmStream: TCustomMemoryStream; const pmcResName: TFileName; const pmcPassword: RawUtf8; pmIsCompressed: Boolean = True); public constructor Create(const pmcFileName: TFileName; const pmcPassword: RawUtf8); destructor Destroy; override; function LoadImage(pmImage: TImage; const pmcImageName: String): Boolean; procedure SaveImage(pmImage: TImage; const pmcImageName: String); overload; procedure SaveImage(pmImageData: TCustomMemoryStream; const pmcImageName: String); overload; end;
Um den letzten Punkt gleich abzuhandeln, hierzu ein paar Benchmark-Werte aus der Anwendung ermittelt mit einem 2MB großen PNG-Bild:
ZIP-Datei Implementierung Durch die Einbindung der Unit mormot.core.zip erhält man Support für ZIP und GZ. Lesen und Schreiben einer ZIP-Datei werden immer getrennt behandelt. Für das Lesen ist die Klasse TZipRead vorhanden und für das Schreiben die Klasse TZipWrite. Die Quelle kann eine Datei oder ein Stream sein. TZipRead kann auch direkt aus einer Ressource, eingebettet in die ausführbare Datei, lesen. Zusätzlich beinhaltet die Unit einige nützliche Funktionen. Beispielhaft sind:
Mediatoren sind eine elegante Möglichkeit Funktionalität zu kapseln und die einfache und sichere Anwendung zu erreichen. Auch wenn das folgende Beispiel unterkomplex ist, ist der Gewinn erkennbar. Hinter der Funktion könnte sich auch ein semi-modaler Dialog mit Fortschrittsanzeige verbergen. Und wer weiß immer, welche Felder genau PProgressInfo enthält? Mit der einfachen Anbindung an einen Mediator erledigt sich das von selbst. Ich wähle nur aus, der Rest wird zuverlässig erledigt. Einmal entwickelt und immer wieder genutzt.
Delphi-Quellcode:
Die Umsetzung der Anbindung ist ein einfacher Aufruf der Funktion Prepare():
type
TZipProgressBarGuiHelper = class(TCustomZipProgressGuiHelper) private FProgressBar: TProgressBar; protected procedure DoOnInfoProgress(pmSender: TObject; pmInfo: PProgressInfo); override; public constructor Create(pmProgressBar: TProgressBar); reintroduce; procedure Prepare(pmZip: TZipAbstract); override; end; procedure TZipProgressBarGuiHelper.DoOnInfoProgress(pmSender: TObject; pmInfo: PProgressInfo); begin if pmInfo.CurrentSize = 0 then begin FProgressBar.Min := 0; FProgressBar.Max := 100; FProgressBar.Position := 0 end else if pmInfo.CurrentSize >= pmInfo.ExpectedSize then FProgressBar.Position := 0 else FProgressBar.Position := pmInfo.Percent; end; procedure TZipProgressBarGuiHelper.Prepare(pmZip: TZipAbstract); begin if pmZip = Nil then Exit; //=> pmZip.ReportDelay := 50; pmZip.OnProgress := DoOnInfoProgress; end;
Delphi-Quellcode:
**Der Begriff Mediator wird hier allgemeiner verwendet, als es der Kontext des gleichnamigen Design-Patterns vorgibt.
var zipWrite: TZipWrite := TZipWrite.Create(MakePath([Executable.ProgramFilePath, 'TestFile.zip']));
try FProgressHelper.Prepare(zipWrite); zipWrite.AddDeflated(fileName); finally zipWrite.Free; end; Nützliche kryptografische Funktionen Das Verzeichnis crypt beherbergt die kryptografischen Klassen und Funktionen. Insgesamt umfasst es ca. 28K Zeilen Quelltext. Dreh- und Angelpunkt ist die Unit mormot.crypt.core. Ein kurzer Auszug aus der Beschreibung gibt einen Einblick in den Inhalt:
Delphi-Quellcode:
Die Funktion CryptDataForCurrentUser kann Daten mittels AES-256-CFB und einem nur dem aktuellen Benutzer bekannten Geheimnis schützen. Für dessen Erstellung wird Windows DPAPI verwendet und die Datei im lokalen AppData-Ordner des Benutzers gespeichert. Zusätzlich kann in der Anwendung noch ein anwendungsspezifischer AppSecret-Wert angegeben werden.
AesPkcs7File('FileName.txt', 'FileName.dat', True, 'TopSecretPassword');
AesPkcs7File('FileName.dat', 'FileName2.txt', False, 'TopSecretPassword'); if HashFileMd5('FileName.txt') = HashFileMd5('FileName2.txt') then ShowMessage('Everything is fine!');
Delphi-Quellcode:
Mit der Kombination aus den Klassen TAesPkcs7Reader/TAesPkcs7Writer und den Funktionen RecordLoadJson/RecordSaveJson ein Lizenzhandling erstellen:
var
plainText, secretText: RawByteString; begin plainText := 'This is a secret text that only I should know.'; secretText := CryptDataForCurrentUser(plainText, 'AppSecret', True); plainText := CryptDataForCurrentUser(secretText, 'AppSecret', False); try ShowMessage(Utf8ToString(plainText)); finally FillZero(plainText); end; end;
Delphi-Quellcode:
Die JSON Deserialisierung ist fehlertolerant! Das heißt, man kann dem Record TLicenseData neue Felder hinzufügen und die Funktion RecordLoadJson lädt auch vorherige Versionen zuverlässig. Damit muss man keine Streaming-Versionen mehr pflegen.
type
TLicenseData = record CustomerNum: Integer; CustomerName: RawUtf8; CustomerAddress: RawUtf8; LicenceDate: TDate; ProductName: RawUtf8; ProductVersion: record Major: Integer; Minor: Integer; end; end; var licData: TLicenseData; begin licData.CustomerNum := 1; licData.CustomerName := 'Thomas'; licData.LicenceDate := Date; licData.ProductName := 'Delphi'; licData.ProductVersion.Major := 11; licData.ProductVersion.Minor := 1; var tmpStream: TMemoryStream := TMemoryStream.Create; try var licStream: TRawByteStringStream := TRawByteStringStream.Create(RecordSaveJson(licData, TypeInfo(TLicenseData))); try var aesWriter: TAesPkcs7Writer := TAesPkcs7Writer.Create(tmpStream, 'TopSecretPassword'); try StreamCopyUntilEnd(licStream, aesWriter); aesWriter.Finish; finally aesWriter.Free; end; finally licStream.Free; end; tmpStream.SaveToFile('LicenseData.lic'); finally tmpStream.Free; end; Write-Speed-Challenge Ein paar Benchmark-Werte mit Hilfe der Beispiel-Anwendung ermittelt:
Zusammenfassung mORMot ist gut dokumentiert. Die Hilfe umfasst mehr als 2500 Seiten. Davon enthalten die ersten ca. 650 Seiten einen sehr lesenswerten allgemeinen Teil, der Rest ist API Dokumentation. mORMot muss nicht in der IDE installierten werden! Es reicht aus, die entsprechenden Bibliothekspfade einzufügen. Es stehen viele Beispiele und ein freundliches Forum zur Verfügung. Wenn mehr Interesse an mORMot besteht, kann ich auch andere Teile in ähnlicher Weise kurz vorstellen. Bis bald... Thomas |
|||||||||||||||||||||
Zitat |
Ansicht |
Linear-Darstellung |
Zur Hybrid-Darstellung wechseln |
Zur Baum-Darstellung wechseln |
ForumregelnEs ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.
BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus. Trackbacks are an
Pingbacks are an
Refbacks are aus
|
|
Nützliche Links |
Heutige Beiträge |
Sitemap |
Suchen |
Code-Library |
Wer ist online |
Alle Foren als gelesen markieren |
Gehe zu... |
LinkBack |
LinkBack URL |
About LinkBacks |