xtool/contrib/DelphiEncryptionCompendium/Source/DECBaseClass.pas

377 lines
12 KiB
ObjectPascal

{*****************************************************************************
The DEC team (see file NOTICE.txt) licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. A copy of this licence is found in the root directory
of this project in the file LICENCE.txt or alternatively at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*****************************************************************************}
unit DECBaseClass;
interface
{$INCLUDE DECOptions.inc}
uses
{$IFDEF FPC}
SysUtils, Classes,
{$ELSE}
System.SysUtils, System.Classes,
{$ENDIF}
Generics.Collections;
type
/// <summary>
/// Class type for the base class from which all other DEC classes inherit
/// in order to be able to create lists of classes, pick an entry of such a
/// list and construct an object out of it
/// </summary>
TDECClass = class of TDECObject;
/// <summary>
/// Generic list of DEC classes with the identity as key
/// </summary>
TDECClassList = class(TDictionary<Int64, TDECClass>)
strict private
/// <summary>
/// Checks if a given class type has the same short class name as given
/// </summary>
/// <param name="Name">
/// Short class name, e.g. HEXL
/// </param>
/// <param name="ClassType">
/// Class reference to check against
/// </param>
/// <returns>
/// true if the class reference is for the given short name
/// </returns>
function DoFindNameShort(const Name: string; const ClassType: TDECClass): Boolean;
/// <summary>
/// Checks if a given class type has the same long class name as given
/// </summary>
/// <param name="Name">
/// Long class name, e.g. TFormat_HEXL
/// </param>
/// <param name="ClassType">
/// Class reference to check against
/// </param>
/// <returns>
/// true if the class reference is for the given long name
/// </returns>
function DoFindNameLong(const Name: string; const ClassType: TClass): Boolean;
public
/// <summary>
/// Tries to find a class type by its name
/// </summary>
/// <param name="Name">
/// Name to look for in the list
/// </param>
/// <returns>
/// Returns the class type if found. if it could not be found a
/// EDECClassNotRegisteredException will be thrown
/// </returns>
function ClassByName(const Name: string): TDECClass;
/// <summary>
/// Tries to find a class type by its numeric identity DEC assigned to it.
/// Useful for file headers, so they can easily encode numerically which
/// cipher class was being used.
/// </summary>
/// <param name="Identity">
/// Identity to look for
/// </param>
/// <returns>
/// Returns the class type of the class with the specified identity value
/// or throws an EDECClassNotRegisteredException exception if no class
/// with the given identity has been found
/// </returns>
function ClassByIdentity(Identity: Int64): TDECClass;
/// <summary>
/// Returns a list of all classes registered in this list
/// </summary>
/// <param name="List">
/// List where the registered classes shall be added to. The string is the
/// long class name, the object the class reference. The list is being
/// cleared first and when an uncreated list is given nothing is being done
/// </param>
procedure GetClassList(List: TStrings);
end;
/// <summary>
/// Parent class of all cryptography and hash implementations
/// </summary>
TDECObject = class(TInterfacedObject)
public
/// <summary>
/// Overrideable but otherwise empty constructor (calls his parent
/// constructor or course)
/// </summary>
constructor Create; virtual;
/// <summary>
/// This function creates a unique Signature for each class using the
/// following naming scheme:
///
/// 'Z' repeated n times (to fill space of 256 chars) + DEC ClassName
///
/// The CRC32 of the generated Signature is used as our unique Identity
///
/// Important Note:
/// DEC 5.2 introduced a bug which breaks backward compatibility with
/// DEC 5.1 by using String instead of AnsiString. This leads to different
/// Identities when using Unicode capable Delphi Versions (Delphi 2009+).
///
/// To restore the *wrong* behavior of DEC 5.2 enable the DEC52_IDENTITY option
/// in the configuration file DECOptions.inc.
///
/// With this and all future versions we will keep backward compatibility.
/// </summary>
class function Identity: Int64;
{$IFDEF X86ASM}
/// <summary>
/// Override FreeInstance to fill allocated Object with zeros, that is
/// safer for any access to invalid Pointers of released Objects.
/// </summary>
procedure FreeInstance; override;
{$ENDIF X86ASM}
/// <summary>
/// Registers this class type in the list of DEC classes (ClassList).
/// Trying to register an already registered class will raise an exception.
/// </summary>
/// <param name="ClassList">
/// List to which the own class type shall be added. This allows subclasses
/// to have their own lists
/// </param>
class procedure RegisterClass(ClassList : TDECClassList);
/// <summary>
/// Removes tthis class type from the list of registered DEC classes
/// (ClassList). Trying to unregister a non registered class is a do nothing
/// operation.
/// </summary>
/// <param name="ClassList">
/// List from which the own class type shall be removed. This allows
/// subclasses to have their own lists
/// </param>
class procedure UnregisterClass(ClassList : TDECClassList);
/// <summary>
/// Returns short Classname of any DEC derrived class. This is the part
/// of the class name after the _ so for THash_RipeMD160 it will be RipeMD160.
/// </summary>
/// <param name="ClassName">
/// Complete class name
/// </param>
/// <returns>
/// Short class name
/// </returns>
class function GetShortClassNameFromName(const ClassName: string): string;
/// <summary>
/// Returns short Classname of any DEC derrived class type. This is the part
/// of the class name after the _ so for THash_RipeMD160 it will be RipeMD160.
/// </summary>
/// <returns>
/// Short class name or empty string if ClassType is nil.
/// </returns>
class function GetShortClassName: string;
end;
var
/// <summary>
/// default used for generating class identities
/// </summary>
IdentityBase: Int64 = $25844852;
/// <summary>
/// Size in bytes used for buffering data read from or written to a stream
/// </summary>
StreamBufferSize: Integer = 8192;
{$IFDEF NEXTGEN}
EmptyStr: string = '';
/// <summary>
/// Pointer to an empty string. For non Nextgen platforms declared in SysUtils
/// for backwards compatibility only. Here declared for NextGen only and
/// should get replaced
/// </summary>
NullStr: PString = @EmptyStr;
{$ENDIF}
implementation
uses
DECUtil, DECCRC;
resourcestring
sClassNotRegistered = 'Class %s is not registered';
sWrongIdentity = 'Another class "%s" with the same identity as "%s" has already been registered';
constructor TDECObject.Create;
begin
inherited Create;
end;
class function TDECObject.Identity: Int64;
var
Signature: {$IFDEF DEC52_IDENTITY}string{$ELSE !DEC52_IDENTITY}RawByteString{$ENDIF !DEC52_IDENTITY};
begin
{$IFDEF DEC52_IDENTITY}
Signature := StringOfChar(#$5A, 256 - Length(ClassName)) + UpperCase(ClassName);
{$IF CompilerVersion >= 24.0}
Result := CRC32(IdentityBase, Signature[Low(Signature)],
Length(Signature) * SizeOf(Signature[Low(Signature)]));
{$ELSE}
Result := CRC32(IdentityBase, Signature[Low(Signature)],
Length(Signature) * SizeOf(Signature[1]));
{$IFEND}
{$ELSE !DEC52_IDENTITY}
Signature := RawByteString(StringOfChar(#$5A, 256 - Length(ClassName)) + UpperCase(ClassName));
{$IF CompilerVersion >= 24.0}
Result := CRC32(IdentityBase, Signature[Low(Signature)],
Length(Signature) * SizeOf(Signature[Low(Signature)]));
{$ELSE}
Result := CRC32(IdentityBase, Signature[1],
Length(Signature) * SizeOf(Signature[1]));
{$IFEND}
{$ENDIF !DEC52_IDENTITY}
end;
class procedure TDECObject.RegisterClass(ClassList : TDECClassList);
begin
ClassList.Add(Identity, self);
end;
{$IFDEF X86ASM}
procedure TDECObject.FreeInstance;
// Override FreeInstance to fill allocated Object with zeros, that is
// safer for any access to invalid Pointers of released Objects
asm
PUSH EBX
PUSH EDI
MOV EBX,EAX
CALL TObject.CleanupInstance
MOV EAX,[EBX]
CALL TObject.InstanceSize
MOV ECX,EAX
MOV EDI,EBX
XOR EAX,EAX
REP STOSB
MOV EAX,EBX
CALL System.@FreeMem
POP EDI
POP EBX
end;
{$ENDIF X86ASM}
class procedure TDECObject.UnregisterClass(ClassList : TDECClassList);
begin
ClassList.Remove(Identity);
end;
class function TDECObject.GetShortClassName: string;
begin
Result := GetShortClassNameFromName(self.ClassName);
end;
class function TDECObject.GetShortClassNameFromName(const ClassName: string): string;
var
i: Integer;
begin
Result := ClassName;
i := Pos('_', Result);
if i > 0 then
Delete(Result, 1, i);
end;
{ TDECClassList }
function TDECClassList.DoFindNameShort(const Name: string; const ClassType: TDECClass): Boolean;
begin
Result := CompareText(ClassType.GetShortClassName, Name) = 0;
end;
function TDECClassList.DoFindNameLong(const Name: string; const ClassType: TClass): Boolean;
var
s: string;
begin
s := Name;
Result := CompareText(ClassType.ClassName, Name) = 0;
end;
function TDECClassList.ClassByIdentity(Identity: Int64): TDECClass;
begin
try
Result := Items[Identity];
except
On EListError do
raise EDECClassNotRegisteredException.CreateResFmt(@sClassNotRegistered,
[IntToHEX(Identity, 8)]);
end;
end;
function TDECClassList.ClassByName(const Name: string): TDECClass;
var
FindNameShort : Boolean;
Pair : TPair<Int64, TDECCLass>;
begin
Result := nil;
if Length(Name) > 0 then
begin
FindNameShort := TDECClass.GetShortClassNameFromName(Name) = Name;
for Pair in self do
begin
if FindNameShort then
begin
if DoFindNameShort(Name, Pair.Value) then
begin
result := Pair.Value;
break;
end;
end
else
if DoFindNameLong(Name, Pair.Value) then
begin
result := Pair.Value;
break;
end;
end;
end;
if Result = nil then
raise EDECClassNotRegisteredException.CreateResFmt(@sClassNotRegistered, [Name]);
end;
procedure TDECClassList.GetClassList(List: TStrings);
var
Pair : TPair<Int64, TDECCLass>;
begin
if List <> nil then
try
List.BeginUpdate;
List.Clear;
for Pair in self do
List.AddObject(Pair.Value.ClassName, TObject(Pair.Value));
finally
List.EndUpdate;
end;
end;
initialization
finalization
end.