diff --git a/EvilLibrary.groupproj b/EvilLibrary.groupproj
new file mode 100644
index 0000000..a0f4b8e
--- /dev/null
+++ b/EvilLibrary.groupproj
@@ -0,0 +1,48 @@
+
+
+ {554334B1-9FC2-45F5-8997-809AA011BA4C}
+
+
+
+
+
+
+
+
+
+
+ Default.Personality.12
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/EvilLibrary.groupproj.local b/EvilLibrary.groupproj.local
new file mode 100644
index 0000000..cd6bd32
--- /dev/null
+++ b/EvilLibrary.groupproj.local
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/EvilLibraryD.dpk b/EvilLibraryD.dpk
new file mode 100644
index 0000000..c3fbe61
--- /dev/null
+++ b/EvilLibraryD.dpk
@@ -0,0 +1,41 @@
+package EvilLibraryD;
+
+{$R *.res}
+{$IFDEF IMPLICITBUILDING This IFDEF should not be used by users}
+{$ALIGN 8}
+{$ASSERTIONS ON}
+{$BOOLEVAL OFF}
+{$DEBUGINFO ON}
+{$EXTENDEDSYNTAX ON}
+{$IMPORTEDDATA ON}
+{$IOCHECKS ON}
+{$LOCALSYMBOLS ON}
+{$LONGSTRINGS ON}
+{$OPENSTRINGS ON}
+{$OPTIMIZATION OFF}
+{$OVERFLOWCHECKS ON}
+{$RANGECHECKS ON}
+{$REFERENCEINFO ON}
+{$SAFEDIVIDE OFF}
+{$STACKFRAMES ON}
+{$TYPEDADDRESS OFF}
+{$VARSTRINGCHECKS ON}
+{$WRITEABLECONST OFF}
+{$MINENUMSIZE 1}
+{$IMAGEBASE $400000}
+{$DEFINE DEBUG}
+{$ENDIF IMPLICITBUILDING}
+{$DESCRIPTION 'EvilWorks.EvilLibrary.Designtime'}
+{$DESIGNONLY}
+{$IMPLICITBUILD ON}
+
+requires
+ rtl,
+ designide,
+ EvilLibraryR;
+
+contains
+ EvilWorks.Vcl.Reg in 'EvilWorks.Vcl.Reg.pas',
+ EvilWorks.Design.HTTPHeadersEditor in 'EvilWorks.Design.HTTPHeadersEditor.pas' {HTTPHeadersPropertyEditorForm};
+
+end.
diff --git a/EvilLibraryD.dproj b/EvilLibraryD.dproj
new file mode 100644
index 0000000..36cb684
--- /dev/null
+++ b/EvilLibraryD.dproj
@@ -0,0 +1,158 @@
+
+
+ {665D088D-3B13-48F3-AE60-C5A293B8222A}
+ EvilLibraryD.dpk
+ 13.4
+ VCL
+ True
+ Debug
+ Win32
+ 1
+ Package
+
+
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Cfg_1
+ true
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ true
+ rtl;$(DCC_UsePackage)
+ true
+ 1050
+ EvilWorks.EvilLibrary.Designtime
+ CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=
+ ..\Bin\$(platform)\$(config)
+ System.Win;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace)
+ 00400000
+
+
+ vcl;$(DCC_UsePackage)
+
+
+ vcl;EvilLibraryR;$(DCC_UsePackage)
+ 1033
+ true
+ CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=
+ Winapi;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)
+
+
+ $(BDS)\bin\delphi_PROJECTICON.ico
+ $(BDS)\bin\default_app.manifest
+ true
+ true
+ true
+ DEBUG;$(DCC_Define)
+ false
+ true
+
+
+ true
+ 1033
+ false
+
+
+ $(BDS)\bin\default_app.manifest
+ $(BDS)\bin\delphi_PROJECTICON.ico
+ false
+ false
+ RELEASE;$(DCC_Define)
+ 0
+ false
+
+
+
+ MainSource
+
+
+
+
+
+
+
+ dfm
+
+
+ Cfg_2
+ Base
+
+
+ Base
+
+
+ Cfg_1
+ Base
+
+
+
+ Delphi.Personality.12
+ Package
+
+
+
+ EvilLibraryD.dpk
+
+
+ True
+ False
+ 1
+ 0
+ 0
+ 0
+ False
+ False
+ False
+ False
+ False
+ 1050
+ 1250
+
+
+
+
+ 1.0.0.0
+
+
+
+
+
+ 1.0.0.0
+
+
+
+
+
+ False
+ True
+
+
+ 12
+
+
+
+
diff --git a/EvilLibraryD.dproj.local b/EvilLibraryD.dproj.local
new file mode 100644
index 0000000..5924f80
--- /dev/null
+++ b/EvilLibraryD.dproj.local
@@ -0,0 +1,16 @@
+
+
+
+ 1899.12.30 00:00:00.000.315,=C:\Dev\Delphi\Components\EvilLibrary\Source\Unit1.pas
+ 1899.12.30 00:00:00.000.561,=C:\Dev\Delphi\Components\EvilLibrary\Source\Unit1.pas
+ 1899.12.30 00:00:00.000.376,C:\Dev\Delphi\Components\EvilLibrary\Source\Unit1.pas=C:\Dev\Delphi\Components\EvilLibrary\Source\EvilWorks.Design.HTTPHeadersEditor.pas
+ 1899.12.30 00:00:00.000.988,C:\Dev\Delphi\Components\EvilLibrary\Source\Unit1.dfm=C:\Dev\Delphi\Components\EvilLibrary\Source\EvilWorks.Design.HTTPHeadersEditor.dfm
+ 1899.12.30 00:00:00.000.988,C:\Dev\Delphi\Components\EvilLibrary\Source\Unit1.pas=C:\Dev\Delphi\Components\EvilLibrary\Source\EvilWorks.Design.HTTPHeadersEditor.pas
+ 1899.12.30 00:00:00.000.677,C:\Dev\Delphi\Projects\Package1.dproj=C:\Dev\Delphi\Components\EvilLibrary\Source\EvilLibraryD.dproj
+ 1899.12.30 00:00:00.000.965,=rtl.dcp
+ 1899.12.30 00:00:00.000.952,C:\Dev\Delphi\Components\EvilLibrary\Source\EvilWorks.Design.HTTPHeadersEditor.pas=
+ 1899.12.30 00:00:00.000.639,=vcl.dcp
+ 1899.12.30 00:00:00.000.142,=C:\Dev\Delphi\Components\EvilLibrary\Source\EvilWorks.Vcl.Reg.pas
+
+
+
diff --git a/EvilLibraryD.identcache b/EvilLibraryD.identcache
new file mode 100644
index 0000000..980df72
Binary files /dev/null and b/EvilLibraryD.identcache differ
diff --git a/EvilLibraryD.res b/EvilLibraryD.res
new file mode 100644
index 0000000..c287ee9
Binary files /dev/null and b/EvilLibraryD.res differ
diff --git a/EvilLibraryR.dpk b/EvilLibraryR.dpk
new file mode 100644
index 0000000..536a221
--- /dev/null
+++ b/EvilLibraryR.dpk
@@ -0,0 +1,58 @@
+package EvilLibraryR;
+
+{$R *.res}
+{$IFDEF IMPLICITBUILDING This IFDEF should not be used by users}
+{$ALIGN 8}
+{$ASSERTIONS ON}
+{$BOOLEVAL OFF}
+{$DEBUGINFO ON}
+{$EXTENDEDSYNTAX ON}
+{$IMPORTEDDATA ON}
+{$IOCHECKS ON}
+{$LOCALSYMBOLS ON}
+{$LONGSTRINGS ON}
+{$OPENSTRINGS ON}
+{$OPTIMIZATION OFF}
+{$OVERFLOWCHECKS OFF}
+{$RANGECHECKS OFF}
+{$REFERENCEINFO ON}
+{$SAFEDIVIDE OFF}
+{$STACKFRAMES ON}
+{$TYPEDADDRESS OFF}
+{$VARSTRINGCHECKS ON}
+{$WRITEABLECONST OFF}
+{$MINENUMSIZE 1}
+{$IMAGEBASE $400000}
+{$DEFINE DEBUG}
+{$ENDIF IMPLICITBUILDING}
+{$DESCRIPTION 'EvilWorks.EvilLibrary.Runtime'}
+{$RUNONLY}
+{$IMPLICITBUILD ON}
+
+requires
+ rtl,
+ vcl,
+ vclimg;
+
+contains
+ EvilWorks.Vcl.BrowseDialog in 'EvilWorks.Vcl.BrowseDialog.pas',
+ EvilWorks.Vcl.ConnectionMonitor in 'EvilWorks.Vcl.ConnectionMonitor.pas',
+ EvilWorks.Vcl.ConsoleIO in 'EvilWorks.Vcl.ConsoleIO.pas',
+ EvilWorks.Vcl.FindFiles in 'EvilWorks.Vcl.FindFiles.pas',
+ EvilWorks.Vcl.FormSettings in 'EvilWorks.Vcl.FormSettings.pas',
+ EvilWorks.Vcl.GenericControl in 'EvilWorks.Vcl.GenericControl.pas',
+ EvilWorks.Vcl.SplitPanel in 'EvilWorks.Vcl.SplitPanel.pas',
+ EvilWorks.Vcl.Timers in 'EvilWorks.Vcl.Timers.pas',
+ EvilWorks.Web.AsyncSockets in 'EvilWorks.Web.AsyncSockets.pas',
+ EvilWorks.Web.HTTP in 'EvilWorks.Web.HTTP.pas',
+ EvilWorks.Web.IRC in 'EvilWorks.Web.IRC.pas',
+ EvilWorks.Web.Twitter in 'EvilWorks.Web.Twitter.pas',
+ EvilWorks.Vcl.VirtualListbox in 'EvilWorks.Vcl.VirtualListbox.pas',
+ EvilWorks.Vcl.TweetsControl in 'EvilWorks.Vcl.TweetsControl.pas',
+ EvilWorks.Vcl.MarkupLabel in 'EvilWorks.Vcl.MarkupLabel.pas',
+ EvilWorks.Vcl.MarkupControl in 'EvilWorks.Vcl.MarkupControl.pas',
+ EvilWorks.Web.TwitterTypes in 'EvilWorks.Web.TwitterTypes.pas',
+ EvilWorks.Vcl.Fullscreen in 'EvilWorks.Vcl.Fullscreen.pas';
+
+end.
+
diff --git a/EvilLibraryR.dproj b/EvilLibraryR.dproj
new file mode 100644
index 0000000..275ac02
--- /dev/null
+++ b/EvilLibraryR.dproj
@@ -0,0 +1,166 @@
+
+
+ {6D3FEB20-736A-4C6D-92A2-3DEAC986BCE9}
+ EvilLibraryR.dpk
+ True
+ Debug
+ 1
+ Package
+ VCL
+ 13.4
+ Win32
+
+
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Cfg_2
+ true
+ true
+
+
+ true
+ rtl;$(DCC_UsePackage)
+ 1050
+ false
+ 00400000
+ false
+ true
+ false
+ false
+ EvilWorks.EvilLibrary.Runtime
+ false
+ Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace)
+ CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=
+ true
+
+
+ vcl;vclimg;$(DCC_UsePackage)
+
+
+ vcl;vclimg;$(DCC_UsePackage)
+ 1033
+ true
+ CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=
+ Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)
+
+
+ 0
+ false
+ RELEASE;$(DCC_Define)
+ false
+
+
+ true
+ true
+ DEBUG;$(DCC_Define)
+ false
+
+
+ true
+ 1033
+
+
+
+ MainSource
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Cfg_2
+ Base
+
+
+ Base
+
+
+ Cfg_1
+ Base
+
+
+
+ Delphi.Personality.12
+ Package
+
+
+
+ EvilLibraryR.dpk
+
+
+ True
+ False
+ 1
+ 0
+ 0
+ 0
+ False
+ False
+ False
+ False
+ False
+ 1050
+ 1250
+
+
+
+
+ 1.0.0.0
+
+
+
+
+
+ 1.0.0.0
+
+
+
+
+ False
+ True
+
+
+ 12
+
+
+
+
diff --git a/EvilLibraryR.dproj.local b/EvilLibraryR.dproj.local
new file mode 100644
index 0000000..7e2e6b1
--- /dev/null
+++ b/EvilLibraryR.dproj.local
@@ -0,0 +1,41 @@
+
+
+
+ 1899.12.30 00:00:00.000.867,C:\Dev\Delphi\Components\EvilLibrary\Source\Unit1.pas=C:\Dev\Delphi\Components\EvilLibrary\Source\EvilWorks.Vcl.VirtualListbox.pas
+ 1899.12.30 00:00:00.000.011,=C:\Dev\Delphi\Components\EvilLibrary\Source\Unit1.pas
+ 1899.12.30 00:00:00.000.516,=C:\Dev\Delphi\Components\EvilLibrary\Source\Unit1.pas
+ 1899.12.30 00:00:00.000.736,=C:\Dev\Delphi\Components\EvilLibrary\Source\Unit1.pas
+ 1899.12.30 00:00:00.000.514,=C:\Dev\Delphi\Components\EvilLibrary\Source\Unit1.pas
+ 1899.12.30 00:00:00.000.039,=C:\Dev\Delphi\Components\EvilLibrary\Source\Unit1.pas
+ 1899.12.30 00:00:00.000.760,C:\Dev\Delphi\Components\EvilLibrary\Source\EvilWorks.Vcl.Reg.pas=
+ 1899.12.30 00:00:00.000.626,=C:\Dev\Delphi\Components\EvilLibrary\Source\Unit1.pas
+ 1899.12.30 00:00:00.000.123,=C:\Dev\Delphi\Components\EvilLibrary\Source\Unit1.pas
+ 1899.12.30 00:00:00.000.142,C:\Dev\Delphi\Components\EvilLibrary\Source\Unit1.pas=C:\Dev\Delphi\Components\EvilLibrary\Source\EvilWorks.Vcl.MarkupControl.pas
+ 1899.12.30 00:00:00.000.531,C:\Dev\Delphi\Components\EvilLibrary\Source\Unit1.pas=C:\Dev\Delphi\Components\EvilLibrary\Source\EvilWorks.Web.ProxyConnector.pas
+ 1899.12.30 00:00:00.000.643,C:\Dev\Delphi\Components\EvilLibrary\Source\EvilLibraryR.dproj=C:\Dev\Delphi\Components\EvilLibrary\Source\EvilLibrary.dproj
+ 1899.12.30 00:00:00.000.180,C:\Dev\Delphi\Components\EvilLibrary\Source\Unit1.pas=C:\Dev\Delphi\Components\EvilLibrary\Source\EvilWorks.Web.Connectors.pas
+ 1899.12.30 00:00:00.000.082,C:\Dev\Delphi\Components\EvilLibrary\Source\Unit1.pas=C:\Dev\Delphi\Components\EvilLibrary\Source\EvilWorks.Vcl.TweetsControl.pas
+ 1899.12.30 00:00:00.000.278,=C:\Dev\Delphi\Components\EvilLibrary\Source\Unit1.pas
+ 1899.12.30 00:00:00.000.174,=C:\Dev\Delphi\Components\EvilLibrary\Source\Unit1.pas
+ 1899.12.30 00:00:00.000.691,=C:\Dev\Delphi\Components\EvilLibrary\Source\Unit1.pas
+ 1899.12.30 00:00:00.000.658,=C:\Dev\Delphi\Components\EvilLibrary\Source\Unit1.pas
+ 1899.12.30 00:00:00.000.908,C:\Dev\Delphi\Components\EvilLibrary\Source\EvilWorks.Vcl.TextDisplay.pas=
+ 1899.12.30 00:00:00.000.676,C:\Dev\Delphi\Components\EvilLibrary\Source\EvilWorks.Vcl.TextDisplay.pas=
+ 1899.12.30 00:00:00.000.656,C:\Dev\Delphi\Components\EvilLibrary\Source\EvilWorks.Web.ProxyConnector.pas=
+ 1899.12.30 00:00:00.000.545,C:\Dev\Delphi\Components\EvilLibrary\Source\EvilWorks.Vcl.Fullscreen.pas=C:\Dev\Delphi\Components\EvilLibrary\Source\Unit1.pas
+ 1899.12.30 00:00:00.000.303,=C:\Dev\Delphi\Components\EvilLibrary\Source\EvilWorks.Vcl.TextDisplay.pas
+ 1899.12.30 00:00:00.000.076,=C:\Dev\Delphi\Components\EvilLibrary\Source\EvilWorks.Vcl.MarkupLabel.pas
+ 1899.12.30 00:00:00.000.712,=C:\Dev\Delphi\Components\EvilLibrary\Source\JSONInspector.pas
+ 1899.12.30 00:00:00.000.670,C:\Dev\Delphi\Components\EvilLibrary\Source\EvilWorks.Web.TwitterTypes.pas=C:\Dev\Delphi\Components\EvilLibrary\Source\Unit1.pas
+ 1899.12.30 00:00:00.000.193,C:\Dev\Delphi\Components\EvilLibrary\Source\EvilWorks.Web.OAuth.pas=C:\Dev\Delphi\Components\EvilLibrary\Source\Unit1.pas
+ 1899.12.30 00:00:00.000.140,C:\Dev\Delphi\Components\EvilLibrary\Source\EvilWorks.VCL.AsyncSockets.pas=C:\Dev\Delphi\Components\EvilLibrary\Source\Unit1.pas
+ 1899.12.30 00:00:00.000.161,C:\Dev\Delphi\Components\EvilLibrary\Source\EvilWorks.Web.AsyncSockets.pas=C:\Temp\EvilWorks.Web.AsyncSockets.pas
+ 1899.12.30 00:00:00.000.853,C:\Dev\Delphi\Components\EvilLibrary\Source\EvilWorks.Web.IRC.pas=C:\Dev\Delphi\Components\EvilLibrary\Source\Unit1.pas
+ 1899.12.30 00:00:00.000.443,C:\Dev\Delphi\Components\EvilLibrary\Source\EvilWorks.VCL.AsyncSockets.pas=
+ 1899.12.30 00:00:00.000.856,C:\Temp\EvilWorks.Web.AsyncSockets.pas=C:\Dev\Delphi\Components\EvilLibrary\Source\EvilWorks.Web.AsyncSockets.pas
+ 1899.12.30 00:00:00.000.096,=C:\Dev\Delphi\Components\EvilLibrary\Source\EvilWorks.Web.Twitter.pas
+ 1899.12.30 00:00:00.000.151,C:\Dev\Delphi\Components\EvilLibrary\Source\EvilWorks.Web.Clients.pas=
+ 1899.12.30 00:00:00.000.919,C:\Dev\Delphi\Components\EvilLibrary\Source\EvilWorks.Web.Connectors.pas=
+ 1899.12.30 00:00:00.000.876,=C:\Dev\Delphi\Components\EvilLibrary\Source\EvilWorks.VirtualTrees.LogTreeView.pas
+
+
diff --git a/EvilLibraryR.identcache b/EvilLibraryR.identcache
new file mode 100644
index 0000000..8905e53
Binary files /dev/null and b/EvilLibraryR.identcache differ
diff --git a/EvilLibraryR.res b/EvilLibraryR.res
new file mode 100644
index 0000000..a64cea3
Binary files /dev/null and b/EvilLibraryR.res differ
diff --git a/EvilLibraryR_project.tvsconfig b/EvilLibraryR_project.tvsconfig
new file mode 100644
index 0000000..d430780
--- /dev/null
+++ b/EvilLibraryR_project.tvsconfig
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/EvilWorks.APi.WInsock2.pas b/EvilWorks.APi.WInsock2.pas
new file mode 100644
index 0000000..8a2c462
--- /dev/null
+++ b/EvilWorks.APi.WInsock2.pas
@@ -0,0 +1,2625 @@
+//
+// EvilLibrary by Vedran Vuk 2010-2012
+//
+// Name: EvilWorks.Api.Winsock2
+// Description: Winsock2 header file, because embarcadero's is, naturally, incomplete.
+// Also some extra utilities, all self contained and lightweight.
+// File last change date: September 14th. 2012
+// File version: Dev 0.0.0
+// Licence: Free.
+//
+
+unit EvilWorks.Api.Winsock2;
+
+interface
+
+uses
+ WinApi.Windows;
+
+{$ALIGN OFF}
+
+
+// Define the current Winsock version. To build an earlier Winsock version
+// application redefine this value prior to including Winsock2.h
+const
+ WINSOCK_VERSION = $0202;
+ WINSOCK2_DLL = 'ws2_32.dll';
+
+type
+ u_char = Byte;
+ u_short = Word;
+ u_int = DWORD;
+ u_long = DWORD;
+
+ // The new type to be used in all instances which refer to sockets.
+ TSocket = u_int;
+ socklen_t = integer;
+
+ WSAEVENT = THandle;
+ PWSAEVENT = ^WSAEVENT;
+ LPWSAEVENT = PWSAEVENT;
+
+{$IFDEF UNICODE}
+ PMBChar = PWideChar;
+{$ELSE}
+ PMBChar = PAnsiChar;
+{$ENDIF}
+
+
+const
+ FD_SETSIZE = 64;
+
+type
+ PFDSet = ^TFDSet;
+
+ TFDSet = packed record
+ fd_count: u_int;
+ fd_array: array [0 .. FD_SETSIZE - 1] of TSocket;
+ end;
+
+ PTimeVal = ^TTimeVal;
+
+ TTimeVal = packed record
+ tv_sec: Longint;
+ tv_usec: Longint;
+ end;
+
+ timeval = TTimeVal;
+
+const
+ IOCPARM_MASK = $7F;
+ IOC_VOID = $20000000;
+ IOC_OUT = $40000000;
+ IOC_IN = $80000000;
+ IOC_INOUT = (IOC_IN or IOC_OUT);
+
+ // get # bytes to read
+ FIONREAD = IOC_OUT or (SizeOf(Longint) shl 16) or (Ord('f') shl 8) or 127;
+ // set/clear non-blocking i/o
+ FIONBIO = IOC_IN or (SizeOf(Longint) shl 16) or (Ord('f') shl 8) or 126;
+ // set/clear async i/o
+ FIOASYNC = IOC_IN or (SizeOf(Longint) shl 16) or (Ord('f') shl 8) or 125;
+
+ // Socket I/O Controls
+
+ // set high watermark
+ SIOCSHIWAT = IOC_IN or (SizeOf(Longint) shl 16) or (Ord('s') shl 8);
+ // get high watermark
+ SIOCGHIWAT = IOC_OUT or (SizeOf(Longint) shl 16) or (Ord('s') shl 8) or 1;
+ // set low watermark
+ SIOCSLOWAT = IOC_IN or (SizeOf(Longint) shl 16) or (Ord('s') shl 8) or 2;
+ // get low watermark
+ SIOCGLOWAT = IOC_OUT or (SizeOf(Longint) shl 16) or (Ord('s') shl 8) or 3;
+ // at oob mark?
+ SIOCATMARK = IOC_OUT or (SizeOf(Longint) shl 16) or (Ord('s') shl 8) or 7;
+
+ // Structures returned by network data base library, taken from the
+ // BSD file netdb.h. All addresses are supplied in host order, and
+ // returned in network order (suitable for use in system calls).
+type
+ PHostEnt = ^THostEnt;
+
+ THostEnt = packed record
+ h_name: PAnsiChar; // official name of host
+ h_aliases: ^PAnsiChar; // alias list
+ h_addrtype: Smallint; // host address type
+ h_length: Smallint; // length of address
+ case Byte of
+ 0:
+ (h_addr_list: ^PAnsiChar); // list of addresses
+ 1:
+ (h_addr: ^PAnsiChar); // address, for backward compat
+ end;
+
+ // It is assumed here that a network number
+ // fits in 32 bits.
+ PNetEnt = ^TNetEnt;
+
+ TNetEnt = packed record
+ n_name: PAnsiChar; // official name of net
+ n_aliases: ^PAnsiChar; // alias list
+ n_addrtype: Smallint; // net address type
+ n_net: u_long; // network #
+ end;
+
+ PServEnt = ^TServEnt;
+
+ TServEnt = packed record
+ s_name: PAnsiChar; // official service name
+ s_aliases: ^PAnsiChar; // alias list
+ s_port: Smallint; // protocol to use
+ s_proto: PAnsiChar; // port #
+ end;
+
+ PProtoEnt = ^TProtoEnt;
+
+ TProtoEnt = packed record
+ p_name: PAnsiChar; // official protocol name
+ p_aliases: ^PAnsiChar; // alias list
+ p_proto: Smallint; // protocol #
+ end;
+
+ // Constants and structures defined by the internet system,
+ // Per RFC 790, September 1981, taken from the BSD file netinet/in.h.
+const
+
+ // Protocols
+ IPPROTO_IP = 0; // dummy for IP
+ IPPROTO_ICMP = 1; // control message protocol
+ IPPROTO_IGMP = 2; // group management protocol
+ IPPROTO_GGP = 3; // gateway^2 (deprecated)
+ IPPROTO_TCP = 6; // TCP
+ IPPROTO_PUP = 12; // pup
+ IPPROTO_UDP = 17; // UDP - user datagram protocol
+ IPPROTO_IDP = 22; // xns idp
+ IPPROTO_ND = 77; // UNOFFICIAL net disk proto
+
+ IPPROTO_RAW = 255; // raw IP packet
+ IPPROTO_MAX = 256;
+
+ // Port/socket numbers: network standard functions
+ IPPORT_ECHO = 7;
+ IPPORT_DISCARD = 9;
+ IPPORT_SYSTAT = 11;
+ IPPORT_DAYTIME = 13;
+ IPPORT_NETSTAT = 15;
+ IPPORT_FTP = 21;
+ IPPORT_TELNET = 23;
+ IPPORT_SMTP = 25;
+ IPPORT_TIMESERVER = 37;
+ IPPORT_NAMESERVER = 42;
+ IPPORT_WHOIS = 43;
+ IPPORT_MTP = 57;
+
+ // Port/socket numbers: host specific functions
+ IPPORT_TFTP = 69;
+ IPPORT_RJE = 77;
+ IPPORT_FINGER = 79;
+ IPPORT_TTYLINK = 87;
+ IPPORT_SUPDUP = 95;
+
+ // UNIX TCP sockets
+ IPPORT_EXECSERVER = 512;
+ IPPORT_LOGINSERVER = 513;
+ IPPORT_CMDSERVER = 514;
+ IPPORT_EFSSERVER = 520;
+
+ // UNIX UDP sockets
+ IPPORT_BIFFUDP = 512;
+ IPPORT_WHOSERVER = 513;
+ IPPORT_ROUTESERVER = 520;
+
+ // Ports < IPPORT_RESERVED are reserved for privileged processes (e.g. root).
+ IPPORT_RESERVED = 1024;
+
+ // Link numbers
+ IMPLINK_IP = 155;
+ IMPLINK_LOWEXPER = 156;
+ IMPLINK_HIGHEXPER = 158;
+
+ TF_DISCONNECT = $01;
+ TF_REUSE_SOCKET = $02;
+ TF_WRITE_BEHIND = $04;
+
+ // This is used instead of -1, since the TSocket type is unsigned.
+ INVALID_SOCKET = TSocket(not (0));
+ SOCKET_ERROR = - 1;
+
+ // The following may be used in place of the address family, socket type, or
+ // protocol in a call to WSASocket to indicate that the corresponding value
+ // should be taken from the supplied WSAPROTOCOL_INFO structure instead of the
+ // parameter itself.
+ FROM_PROTOCOL_INFO = - 1;
+
+ // Types
+ SOCK_STREAM = 1; { stream socket }
+ SOCK_DGRAM = 2; { datagram socket }
+ SOCK_RAW = 3; { raw-protocol interface }
+ SOCK_RDM = 4; { reliably-delivered message }
+ SOCK_SEQPACKET = 5; { sequenced packet stream }
+
+ // Option flags per-socket.
+ SO_DEBUG = $0001; // turn on debugging info recording
+ SO_ACCEPTCONN = $0002; // socket has had listen()
+ SO_REUSEADDR = $0004; // allow local address reuse
+ SO_KEEPALIVE = $0008; // keep connections alive
+ SO_DONTROUTE = $0010; // just use interface addresses
+ SO_BROADCAST = $0020; // permit sending of broadcast msgs
+ SO_USELOOPBACK = $0040; // bypass hardware when possible
+ SO_LINGER = $0080; // linger on close if data present
+ SO_OOBINLINE = $0100; // leave received OOB data in line
+
+ SO_DONTLINGER = not SO_LINGER;
+ SO_EXCLUSIVEADDRUSE = not SO_REUSEADDR; // disallow local address reuse
+
+ // Additional options.
+
+ SO_SNDBUF = $1001; // send buffer size
+ SO_RCVBUF = $1002; // receive buffer size
+ SO_SNDLOWAT = $1003; // send low-water mark
+ SO_RCVLOWAT = $1004; // receive low-water mark
+ SO_SNDTIMEO = $1005; // send timeout
+ SO_RCVTIMEO = $1006; // receive timeout
+ SO_ERROR = $1007; // get error status and clear
+ SO_TYPE = $1008; // get socket type
+
+ // Options for connect and disconnect data and options.
+ // Used only by non-TCP/IP transports such as DECNet, OSI TP4, etc.
+ SO_CONNDATA = $7000;
+ SO_CONNOPT = $7001;
+ SO_DISCDATA = $7002;
+ SO_DISCOPT = $7003;
+ SO_CONNDATALEN = $7004;
+ SO_CONNOPTLEN = $7005;
+ SO_DISCDATALEN = $7006;
+ SO_DISCOPTLEN = $7007;
+
+ // Option for opening sockets for synchronous access.
+ SO_OPENTYPE = $7008;
+ SO_SYNCHRONOUS_ALERT = $10;
+ SO_SYNCHRONOUS_NONALERT = $20;
+
+ // Other NT-specific options.
+ SO_MAXDG = $7009;
+ SO_MAXPATHDG = $700A;
+ SO_UPDATE_ACCEPT_CONTEXT = $700B;
+ SO_UPDATE_CONNECT_CONTEXT = $7010;
+ SO_CONNECT_TIME = $700C;
+
+ // TCP options.
+ TCP_NODELAY = $0001;
+ TCP_BSDURGENT = $7000;
+
+ // WinSock 2 extension -- new options
+ SO_GROUP_ID = $2001; // ID of a socket group
+ SO_GROUP_PRIORITY = $2002; // the relative priority within a group
+ SO_MAX_MSG_SIZE = $2003; // maximum message size
+ SO_Protocol_InfoA = $2004; // WSAPROTOCOL_INFOA structure
+ SO_Protocol_InfoW = $2005; // WSAPROTOCOL_INFOW structure
+{$IFDEF UNICODE}
+ SO_Protocol_Info = SO_Protocol_InfoW;
+{$ELSE}
+ SO_Protocol_Info = SO_Protocol_InfoA;
+{$ENDIF}
+ PVD_CONFIG = $3001; // configuration info for service provider
+ SO_CONDITIONAL_ACCEPT = $3002; // enable true conditional accept:
+ // connection is not ack-ed to the
+ // other side until conditional
+ // function returns CF_ACCEPT
+
+// Address families.
+ AF_UNSPEC = 0; // unspecified
+ AF_UNIX = 1; // local to host (pipes, portals)
+ AF_INET = 2; // Internet protocol Version 4: UDP, TCP, etc.
+ AF_IMPLINK = 3; // arpanet imp addresses
+ AF_PUP = 4; // pup protocols: e.g. BSP
+ AF_CHAOS = 5; // mit CHAOS protocols
+ AF_IPX = 6; // IPX and SPX
+ AF_NS = AF_IPX; // XEROX NS protocols
+ AF_ISO = 7; // ISO protocols
+ AF_OSI = AF_ISO; // OSI is ISO
+ AF_ECMA = 8; // european computer manufacturers
+ AF_DATAKIT = 9; // datakit protocols
+ AF_CCITT = 10; // CCITT protocols, X.25 etc
+ AF_SNA = 11; // IBM SNA
+ AF_DECnet = 12; // DECnet
+ AF_DLI = 13; // Direct data link interface
+ AF_LAT = 14; // LAT
+ AF_HYLINK = 15; // NSC Hyperchannel
+ AF_APPLETALK = 16; // AppleTalk
+ AF_NETBIOS = 17; // NetBios-style addresses
+ AF_VOICEVIEW = 18; // VoiceView
+ AF_FIREFOX = 19; // FireFox
+ AF_UNKNOWN1 = 20; // Somebody is using this!
+ AF_BAN = 21; // Banyan
+ AF_ATM = 22; // Native ATM Services
+ AF_INET6 = 23; // Internet protocol Version 6
+ AF_CLUSTER = 24; // Microsoft Wolfpack
+ AF_12844 = 25; // IEEE 1284.4 WG AF
+ AF_IRDA = 26; // IrDA
+ AF_NETDES = 28; // Network Designers OSI & gateway enabled protocols
+
+ AF_MAX = 29;
+
+
+ // Protocol families, same as address families for now.
+
+ PF_UNSPEC = AF_UNSPEC;
+ PF_UNIX = AF_UNIX;
+ PF_INET = AF_INET;
+ PF_IMPLINK = AF_IMPLINK;
+ PF_PUP = AF_PUP;
+ PF_CHAOS = AF_CHAOS;
+ PF_NS = AF_NS;
+ PF_IPX = AF_IPX;
+ PF_ISO = AF_ISO;
+ PF_OSI = AF_OSI;
+ PF_ECMA = AF_ECMA;
+ PF_DATAKIT = AF_DATAKIT;
+ PF_CCITT = AF_CCITT;
+ PF_SNA = AF_SNA;
+ PF_DECnet = AF_DECnet;
+ PF_DLI = AF_DLI;
+ PF_LAT = AF_LAT;
+ PF_HYLINK = AF_HYLINK;
+ PF_APPLETALK = AF_APPLETALK;
+ PF_VOICEVIEW = AF_VOICEVIEW;
+ PF_FIREFOX = AF_FIREFOX;
+ PF_UNKNOWN1 = AF_UNKNOWN1;
+ PF_BAN = AF_BAN;
+ PF_ATM = AF_ATM;
+ PF_INET6 = AF_INET6;
+
+ PF_MAX = AF_MAX;
+
+ WSAID_CONNECTEX: TGUID = (D1: $25A207B9; D2: $DDF3; D3: $4660; D4: ($8E, $E9, $76, $E5, $8C, $74, $06, $3E));
+
+ WSAID_TRANSMITFILE: TGUID = (D1: $B5367DF0; D2: $CBAC; D3: $11CF; D4: ($95, $CA, $00, $80, $5F, $48, $A1, $92));
+
+ //
+ // Flags used in "hints" argument to getaddrinfo()
+ // - AI_ADDRCONFIG is supported starting with Vista
+ // - default is AI_ADDRCONFIG ON whether the flag is set or not
+ // because the performance penalty in not having ADDRCONFIG in
+ // the multi-protocol stack environment is severe;
+ // this defaulting may be disabled by specifying the AI_ALL flag,
+ // in that case AI_ADDRCONFIG must be EXPLICITLY specified to
+ // enable ADDRCONFIG behavior
+ //
+
+ AI_PASSIVE = $00000001; // Socket address will be used in bind() call
+ AI_CANONNAME = $00000002; // Return canonical name in first ai_canonname
+ AI_NUMERICHOST = $00000004; // Nodename must be a numeric address string
+ AI_NUMERICSERV = $00000008; // Servicename must be a numeric port number
+
+ AI_ALL = $00000100; // Query both IP6 and IP4 with AI_V4MAPPED
+ AI_ADDRCONFIG = $00000400; // Resolution only if global address configured
+ AI_V4MAPPED = $00000800; // On v6 failure, query v4 and convert to V4MAPPED format
+
+ AI_NON_AUTHORITATIVE = $00004000; // LUP_NON_AUTHORITATIVE
+ AI_SECURE = $00008000; // LUP_SECURE
+ AI_RETURN_PREFERRED_NAMES = $00010000; // LUP_RETURN_PREFERRED_NAMES
+
+ AI_FQDN = $00020000; // Return the FQDN in ai_canonname
+ AI_FILESERVER = $00040000; // Resolving fileserver name resolution
+
+type
+ // IPv4 Address
+ SunB = packed record
+ s_b1, s_b2, s_b3, s_b4: u_char;
+ end;
+
+ SunW = packed record
+ s_w1, s_w2: u_short;
+ end;
+
+ in_addr = packed record
+ case integer of
+ 0:
+ (S_un_b: SunB);
+ 1:
+ (S_un_w: SunW);
+ 2:
+ (S_addr: u_long);
+ end;
+
+ TInAddr = in_addr;
+ PInAddr = ^TInAddr;
+
+ // IPv6 address
+
+ in6_addr = packed record
+ case integer of
+ 0:
+ (Bytes: array [0 .. 15] of Byte);
+ 1:
+ (Words: array [0 .. 7] of Word);
+ end;
+
+ TIn6Addr = in6_addr;
+ PIn6Addr = ^TIn6Addr;
+
+ in_addr6 = in6_addr;
+
+ // Structure used by kernel to store most addresses.
+
+ TSockAddrIn = packed record
+ case integer of
+ 0:
+ (sin_family: u_short;
+ sin_port: u_short;
+ sin_addr: TInAddr;
+ sin_zero: array [0 .. 7] of Char);
+ 1:
+ (sa_family: u_short;
+ sa_data: array [0 .. 13] of Char)
+ end;
+
+ PSockAddrIn = ^TSockAddrIn;
+ TSockAddr = TSockAddrIn;
+ PSockAddr = ^TSockAddr;
+ SOCKADDR = TSockAddr;
+ SOCKADDR_IN = TSockAddrIn;
+
+ TSockAddrIn6 = packed record
+ sin6_family: short;
+ sin6_port: u_short;
+ sin6_flowinfo: u_long;
+ sin6_addr: in6_addr;
+ sin6_scope_id: u_long;
+ end;
+
+ PSockAddrIn6 = ^TSockAddrIn6;
+ SOCKADDR_IN6 = TSockAddrIn6;
+
+ // Structure used by kernel to pass protocol information in raw sockets.
+ PSockProto = ^TSockProto;
+
+ TSockProto = packed record
+ sp_family: u_short;
+ sp_protocol: u_short;
+ end;
+
+ // Structure used for manipulating linger option.
+ PLinger = ^TLinger;
+
+ TLinger = packed record
+ l_onoff: u_short;
+ l_linger: u_short;
+ end;
+
+ PADDRINFOA = ^ADDRINFOA;
+ PPADDRINFOA = ^PADDRINFOA;
+
+ ADDRINFOA = record
+ ai_flags: integer;
+ ai_family: integer;
+ ai_socktype: integer;
+ ai_protocol: integer;
+ ai_addrlen: cardinal; // size_t
+ AI_CANONNAME: PAnsiChar;
+ ai_addr: PSockAddr;
+ ai_next: PADDRINFOA;
+ end;
+
+ TAddrInfoA = ADDRINFOA;
+
+ PADDRINFOW = ^ADDRINFOW;
+ PPADDRINFOW = ^PADDRINFOW;
+
+ ADDRINFOW = record
+ ai_flags: integer;
+ ai_family: integer;
+ ai_socktype: integer;
+ ai_protocol: integer;
+ ai_addrlen: cardinal; // size_t
+ AI_CANONNAME: PWideChar;
+ ai_addr: PSockAddr;
+ ai_next: PADDRINFOW;
+ end;
+
+ TAddrInfoW = ADDRINFOW;
+
+{$IFDEF UNICODE}
+ addrinfo = ADDRINFOW;
+ TAddrInfo = TAddrInfoW;
+ PAddrInfo = PADDRINFOW;
+ PPAddrInfo = PPADDRINFOW;
+{$ELSE}
+ addrinfo = ADDRINFOA;
+ TAddrInfo = TAddrInfoA;
+ PAddrInfo = PADDRINFOA;
+ PPAddrInfo = PPADDRINFOA;
+{$ENDIF}
+
+
+const
+ INADDR_ANY = $00000000;
+ INADDR_LOOPBACK = $7F000001;
+ INADDR_BROADCAST = $FFFFFFFF;
+ INADDR_NONE = $FFFFFFFF;
+
+ ADDR_ANY = INADDR_ANY;
+
+ SOL_SOCKET = $FFFF; // options for socket level
+
+ MSG_OOB = $1; // process out-of-band data
+ MSG_PEEK = $2; // peek at incoming message
+ MSG_DONTROUTE = $4; // send without using routing tables
+ MSG_WAITALL = $8; // do not complete until packet is completely filled
+
+ MSG_PARTIAL = $8000; // partial send or recv for message xport
+
+ // WinSock 2 extension -- new flags for WSASend(), WSASendTo(), WSARecv() and WSARecvFrom()
+ MSG_INTERRUPT = $10; // send/recv in the interrupt context
+ MSG_MAXIOVLEN = 16;
+
+
+ // Define constant based on rfc883, used by gethostbyxxxx() calls.
+
+ MAXGETHOSTSTRUCT = 1024;
+
+ // Maximum queue length specifiable by listen.
+ SOMAXCONN = $7FFFFFFF;
+
+ // WinSock 2 extension -- bit values and indices for FD_XXX network events
+ FD_READ_BIT = 0;
+ FD_WRITE_BIT = 1;
+ FD_OOB_BIT = 2;
+ FD_ACCEPT_BIT = 3;
+ FD_CONNECT_BIT = 4;
+ FD_CLOSE_BIT = 5;
+ FD_QOS_BIT = 6;
+ FD_GROUP_QOS_BIT = 7;
+
+ FD_MAX_EVENTS = 8;
+
+ FD_READ = (1 shl FD_READ_BIT);
+ FD_WRITE = (1 shl FD_WRITE_BIT);
+ FD_OOB = (1 shl FD_OOB_BIT);
+ FD_ACCEPT = (1 shl FD_ACCEPT_BIT);
+ FD_CONNECT = (1 shl FD_CONNECT_BIT);
+ FD_CLOSE = (1 shl FD_CLOSE_BIT);
+ FD_QOS = (1 shl FD_QOS_BIT);
+ FD_GROUP_QOS = (1 shl FD_GROUP_QOS_BIT);
+
+ FD_ALL_EVENTS = (1 shl FD_MAX_EVENTS) - 1;
+
+ // All Windows Sockets error constants are biased by WSABASEERR from the "normal"
+
+ WSABASEERR = 10000;
+
+ // Windows Sockets definitions of regular Microsoft C error constants
+
+ WSAEINTR = WSABASEERR + 4;
+ WSAEBADF = WSABASEERR + 9;
+ WSAEACCES = WSABASEERR + 13;
+ WSAEFAULT = WSABASEERR + 14;
+ WSAEINVAL = WSABASEERR + 22;
+ WSAEMFILE = WSABASEERR + 24;
+
+ // Windows Sockets definitions of regular Berkeley error constants
+
+ WSAEWOULDBLOCK = WSABASEERR + 35;
+ WSAEINPROGRESS = WSABASEERR + 36;
+ WSAEALREADY = WSABASEERR + 37;
+ WSAENOTSOCK = WSABASEERR + 38;
+ WSAEDESTADDRREQ = WSABASEERR + 39;
+ WSAEMSGSIZE = WSABASEERR + 40;
+ WSAEPROTOTYPE = WSABASEERR + 41;
+ WSAENOPROTOOPT = WSABASEERR + 42;
+ WSAEPROTONOSUPPORT = WSABASEERR + 43;
+ WSAESOCKTNOSUPPORT = WSABASEERR + 44;
+ WSAEOPNOTSUPP = WSABASEERR + 45;
+ WSAEPFNOSUPPORT = WSABASEERR + 46;
+ WSAEAFNOSUPPORT = WSABASEERR + 47;
+ WSAEADDRINUSE = WSABASEERR + 48;
+ WSAEADDRNOTAVAIL = WSABASEERR + 49;
+ WSAENETDOWN = WSABASEERR + 50;
+ WSAENETUNREACH = WSABASEERR + 51;
+ WSAENETRESET = WSABASEERR + 52;
+ WSAECONNABORTED = WSABASEERR + 53;
+ WSAECONNRESET = WSABASEERR + 54;
+ WSAENOBUFS = WSABASEERR + 55;
+ WSAEISCONN = WSABASEERR + 56;
+ WSAENOTCONN = WSABASEERR + 57;
+ WSAESHUTDOWN = WSABASEERR + 58;
+ WSAETOOMANYREFS = WSABASEERR + 59;
+ WSAETIMEDOUT = WSABASEERR + 60;
+ WSAECONNREFUSED = WSABASEERR + 61;
+ WSAELOOP = WSABASEERR + 62;
+ WSAENAMETOOLONG = WSABASEERR + 63;
+ WSAEHOSTDOWN = WSABASEERR + 64;
+ WSAEHOSTUNREACH = WSABASEERR + 65;
+ WSAENOTEMPTY = WSABASEERR + 66;
+ WSAEPROCLIM = WSABASEERR + 67;
+ WSAEUSERS = WSABASEERR + 68;
+ WSAEDQUOT = WSABASEERR + 69;
+ WSAESTALE = WSABASEERR + 70;
+ WSAEREMOTE = WSABASEERR + 71;
+
+ // Extended Windows Sockets error constant definitions
+
+ WSASYSNOTREADY = WSABASEERR + 91;
+ WSAVERNOTSUPPORTED = WSABASEERR + 92;
+ WSANOTINITIALISED = WSABASEERR + 93;
+ WSAEDISCON = WSABASEERR + 101;
+ WSAENOMORE = WSABASEERR + 102;
+ WSAECANCELLED = WSABASEERR + 103;
+ WSAEINVALIDPROCTABLE = WSABASEERR + 104;
+ WSAEINVALIDPROVIDER = WSABASEERR + 105;
+ WSAEPROVIDERFAILEDINIT = WSABASEERR + 106;
+ WSASYSCALLFAILURE = WSABASEERR + 107;
+ WSASERVICE_NOT_FOUND = WSABASEERR + 108;
+ WSATYPE_NOT_FOUND = WSABASEERR + 109;
+ WSA_E_NO_MORE = WSABASEERR + 110;
+ WSA_E_CANCELLED = WSABASEERR + 111;
+ WSAEREFUSED = WSABASEERR + 112;
+
+ { Error return codes from gethostbyname() and gethostbyaddr()
+ (when using the resolver). Note that these errors are
+ retrieved via WSAGetLastError() and must therefore follow
+ the rules for avoiding clashes with error numbers from
+ specific implementations or language run-time systems.
+ For this reason the codes are based at WSABASEERR+1001.
+ Note also that [WSA]NO_ADDRESS is defined only for
+ compatibility purposes. }
+
+ // Authoritative Answer: Host not found
+ WSAHOST_NOT_FOUND = WSABASEERR + 1001;
+ HOST_NOT_FOUND = WSAHOST_NOT_FOUND;
+
+ // Non-Authoritative: Host not found, or SERVERFAIL
+ WSATRY_AGAIN = WSABASEERR + 1002;
+ TRY_AGAIN = WSATRY_AGAIN;
+
+ // Non recoverable errors, FORMERR, REFUSED, NOTIMP
+ WSANO_RECOVERY = WSABASEERR + 1003;
+ NO_RECOVERY = WSANO_RECOVERY;
+
+ // Valid name, no data record of requested type
+ WSANO_DATA = WSABASEERR + 1004;
+ NO_DATA = WSANO_DATA;
+
+ // no address, look for MX record
+ WSANO_ADDRESS = WSANO_DATA;
+ NO_ADDRESS = WSANO_ADDRESS;
+
+ // Define QOS related error return codes
+
+ WSA_QOS_RECEIVERS = WSABASEERR + 1005; // at least one Reserve has arrived
+ WSA_QOS_SENDERS = WSABASEERR + 1006; // at least one Path has arrived
+ WSA_QOS_NO_SENDERS = WSABASEERR + 1007; // there are no senders
+ WSA_QOS_NO_RECEIVERS = WSABASEERR + 1008; // there are no receivers
+ WSA_QOS_REQUEST_CONFIRMED = WSABASEERR + 1009; // Reserve has been confirmed
+ WSA_QOS_ADMISSION_FAILURE = WSABASEERR + 1010; // error due to lack of resources
+ WSA_QOS_POLICY_FAILURE = WSABASEERR + 1011; // rejected for administrative reasons - bad credentials
+ WSA_QOS_BAD_STYLE = WSABASEERR + 1012; // unknown or conflicting style
+ WSA_QOS_BAD_OBJECT = WSABASEERR + 1013;
+ // problem with some part of the filterspec or providerspecific buffer in general
+ WSA_QOS_TRAFFIC_CTRL_ERROR = WSABASEERR + 1014; // problem with some part of the flowspec
+ WSA_QOS_GENERIC_ERROR = WSABASEERR + 1015; // general error
+ WSA_QOS_ESERVICETYPE = WSABASEERR + 1016; // invalid service type in flowspec
+ WSA_QOS_EFLOWSPEC = WSABASEERR + 1017; // invalid flowspec
+ WSA_QOS_EPROVSPECBUF = WSABASEERR + 1018; // invalid provider specific buffer
+ WSA_QOS_EFILTERSTYLE = WSABASEERR + 1019; // invalid filter style
+ WSA_QOS_EFILTERTYPE = WSABASEERR + 1020; // invalid filter type
+ WSA_QOS_EFILTERCOUNT = WSABASEERR + 1021; // incorrect number of filters
+ WSA_QOS_EOBJLENGTH = WSABASEERR + 1022; // invalid object length
+ WSA_QOS_EFLOWCOUNT = WSABASEERR + 1023; // incorrect number of flows
+ WSA_QOS_EUNKOWNPSOBJ = WSABASEERR + 1024; // unknown object in provider specific buffer
+ WSA_QOS_EPOLICYOBJ = WSABASEERR + 1025; // invalid policy object in provider specific buffer
+ WSA_QOS_EFLOWDESC = WSABASEERR + 1026; // invalid flow descriptor in the list
+ WSA_QOS_EPSFLOWSPEC = WSABASEERR + 1027; // inconsistent flow spec in provider specific buffer
+ WSA_QOS_EPSFILTERSPEC = WSABASEERR + 1028; // invalid filter spec in provider specific buffer
+ WSA_QOS_ESDMODEOBJ = WSABASEERR + 1029; // invalid shape discard mode object in provider specific buffer
+ WSA_QOS_ESHAPERATEOBJ = WSABASEERR + 1030; // invalid shaping rate object in provider specific buffer
+ WSA_QOS_RESERVED_PETYPE = WSABASEERR + 1031; // reserved policy element in provider specific buffer
+
+ { WinSock 2 extension -- new error codes and type definition }
+ WSA_IO_PENDING = ERROR_IO_PENDING;
+ WSA_IO_INCOMPLETE = ERROR_IO_INCOMPLETE;
+ WSA_INVALID_HANDLE = ERROR_INVALID_HANDLE;
+ WSA_INVALID_PARAMETER = ERROR_INVALID_PARAMETER;
+ WSA_NOT_ENOUGH_MEMORY = ERROR_NOT_ENOUGH_MEMORY;
+ WSA_OPERATION_ABORTED = ERROR_OPERATION_ABORTED;
+ WSA_INVALID_EVENT = WSAEVENT(nil);
+ WSA_MAXIMUM_WAIT_EVENTS = MAXIMUM_WAIT_OBJECTS;
+ WSA_WAIT_FAILED = $FFFFFFFF;
+ WSA_WAIT_EVENT_0 = WAIT_OBJECT_0;
+ WSA_WAIT_IO_COMPLETION = WAIT_IO_COMPLETION;
+ WSA_WAIT_TIMEOUT = WAIT_TIMEOUT;
+ WSA_INFINITE = INFINITE;
+
+ { Windows Sockets errors redefined as regular Berkeley error constants.
+ These are commented out in Windows NT to avoid conflicts with errno.h.
+ Use the WSA constants instead. }
+
+ EWOULDBLOCK = WSAEWOULDBLOCK;
+ EINPROGRESS = WSAEINPROGRESS;
+ EALREADY = WSAEALREADY;
+ ENOTSOCK = WSAENOTSOCK;
+ EDESTADDRREQ = WSAEDESTADDRREQ;
+ EMSGSIZE = WSAEMSGSIZE;
+ EPROTOTYPE = WSAEPROTOTYPE;
+ ENOPROTOOPT = WSAENOPROTOOPT;
+ EPROTONOSUPPORT = WSAEPROTONOSUPPORT;
+ ESOCKTNOSUPPORT = WSAESOCKTNOSUPPORT;
+ EOPNOTSUPP = WSAEOPNOTSUPP;
+ EPFNOSUPPORT = WSAEPFNOSUPPORT;
+ EAFNOSUPPORT = WSAEAFNOSUPPORT;
+ EADDRINUSE = WSAEADDRINUSE;
+ EADDRNOTAVAIL = WSAEADDRNOTAVAIL;
+ ENETDOWN = WSAENETDOWN;
+ ENETUNREACH = WSAENETUNREACH;
+ ENETRESET = WSAENETRESET;
+ ECONNABORTED = WSAECONNABORTED;
+ ECONNRESET = WSAECONNRESET;
+ ENOBUFS = WSAENOBUFS;
+ EISCONN = WSAEISCONN;
+ ENOTCONN = WSAENOTCONN;
+ ESHUTDOWN = WSAESHUTDOWN;
+ ETOOMANYREFS = WSAETOOMANYREFS;
+ ETIMEDOUT = WSAETIMEDOUT;
+ ECONNREFUSED = WSAECONNREFUSED;
+ ELOOP = WSAELOOP;
+ ENAMETOOLONG = WSAENAMETOOLONG;
+ EHOSTDOWN = WSAEHOSTDOWN;
+ EHOSTUNREACH = WSAEHOSTUNREACH;
+ ENOTEMPTY = WSAENOTEMPTY;
+ EPROCLIM = WSAEPROCLIM;
+ EUSERS = WSAEUSERS;
+ EDQUOT = WSAEDQUOT;
+ ESTALE = WSAESTALE;
+ EREMOTE = WSAEREMOTE;
+
+ WSADESCRIPTION_LEN = 256;
+ WSASYS_STATUS_LEN = 128;
+
+type
+ PWSAData = ^TWSAData;
+
+ TWSAData = packed record
+ wVersion: Word;
+ wHighVersion: Word;
+ szDescription: array [0 .. WSADESCRIPTION_LEN] of AnsiChar;
+ szSystemStatus: array [0 .. WSASYS_STATUS_LEN] of AnsiChar;
+ iMaxSockets: Word;
+ iMaxUdpDg: Word;
+ lpVendorInfo: PAnsiChar;
+ end;
+
+ { WSAOVERLAPPED = Record
+ Internal: LongInt;
+ InternalHigh: LongInt;
+ Offset: LongInt;
+ OffsetHigh: LongInt;
+ hEvent: WSAEVENT;
+ end; }
+ WSAOVERLAPPED = TOverlapped;
+ TWSAOverlapped = WSAOVERLAPPED;
+ PWSAOverlapped = ^WSAOVERLAPPED;
+ LPWSAOVERLAPPED = PWSAOverlapped;
+
+ { WinSock 2 extension -- WSABUF and QOS struct, include qos.h }
+ { to pull in FLOWSPEC and related definitions }
+
+ WSABUF = packed record
+ len: u_long; { the length of the buffer }
+ buf: pointer; { the pointer to the buffer }
+ end { WSABUF };
+
+ PWSABUF = ^WSABUF;
+ LPWSABUF = PWSABUF;
+
+ TServiceType = Longint;
+
+ TFlowSpec = packed record
+ TokenRate, // In Bytes/sec
+ TokenBucketSize, // In Bytes
+ PeakBandwidth, // In Bytes/sec
+ Latency, // In microseconds
+ DelayVariation: Longint; // In microseconds
+ ServiceType: TServiceType;
+ MaxSduSize, MinimumPolicedSize: Longint; // In Bytes
+ end;
+
+ PFlowSpec = ^TFlowSpec;
+
+ QOS = packed record
+ SendingFlowspec: TFlowSpec; { the flow spec for data sending }
+ ReceivingFlowspec: TFlowSpec; { the flow spec for data receiving }
+ ProviderSpecific: WSABUF; { additional provider specific stuff }
+ end;
+
+ TQualityOfService = QOS;
+ PQOS = ^QOS;
+ LPQOS = PQOS;
+
+const
+ SERVICETYPE_NOTRAFFIC = $00000000; // No data in this direction
+ SERVICETYPE_BESTEFFORT = $00000001; // Best Effort
+ SERVICETYPE_CONTROLLEDLOAD = $00000002; // Controlled Load
+ SERVICETYPE_GUARANTEED = $00000003; // Guaranteed
+ SERVICETYPE_NETWORK_UNAVAILABLE = $00000004; // Used to notify change to user
+ SERVICETYPE_GENERAL_INFORMATION = $00000005; // corresponds to "General Parameters" defined by IntServ
+ SERVICETYPE_NOCHANGE = $00000006;
+ // used to indicate that the flow spec contains no change from any previous one
+ // to turn on immediate traffic control, OR this flag with the ServiceType field in teh FLOWSPEC
+ SERVICE_IMMEDIATE_TRAFFIC_CONTROL = $80000000;
+
+ // WinSock 2 extension -- manifest constants for return values of the condition function
+ CF_ACCEPT = $0000;
+ CF_REJECT = $0001;
+ CF_DEFER = $0002;
+
+ // WinSock 2 extension -- manifest constants for shutdown()
+ SD_RECEIVE = $00;
+ SD_SEND = $01;
+ SD_BOTH = $02;
+
+ // WinSock 2 extension -- data type and manifest constants for socket groups
+ SG_UNCONSTRAINED_GROUP = $01;
+ SG_CONSTRAINED_GROUP = $02;
+
+type
+ GROUP = DWORD;
+
+ // WinSock 2 extension -- data type for WSAEnumNetworkEvents()
+ TWSANetworkEvents = record
+ lNetworkEvents: Longint;
+ iErrorCode: array [0 .. FD_MAX_EVENTS - 1] of integer;
+ end;
+
+ PWSANetworkEvents = ^TWSANetworkEvents;
+ LPWSANetworkEvents = PWSANetworkEvents;
+
+ // WinSock 2 extension -- WSAPROTOCOL_INFO structure
+
+{$IFNDEF ver130}
+
+ TGUID = packed record
+ D1: Longint;
+ D2: Word;
+ D3: Word;
+ D4: array [0 .. 7] of Byte;
+ end;
+
+ PGUID = ^TGUID;
+{$ENDIF}
+ LPGUID = PGUID;
+
+ // WinSock 2 extension -- WSAPROTOCOL_INFO manifest constants
+const
+ MAX_PROTOCOL_CHAIN = 7;
+ BASE_PROTOCOL = 1;
+ LAYERED_PROTOCOL = 0;
+ WSAPROTOCOL_LEN = 255;
+
+type
+ TWSAProtocolChain = record
+ ChainLen: integer; // the length of the chain,
+ // length = 0 means layered protocol,
+ // length = 1 means base protocol,
+ // length > 1 means protocol chain
+ ChainEntries: array [0 .. MAX_PROTOCOL_CHAIN - 1] of Longint; // a list of dwCatalogEntryIds
+ end;
+
+type
+ TWSAProtocol_InfoA = record
+ dwServiceFlags1: Longint;
+ dwServiceFlags2: Longint;
+ dwServiceFlags3: Longint;
+ dwServiceFlags4: Longint;
+ dwProviderFlags: Longint;
+ ProviderId: TGUID;
+ dwCatalogEntryId: Longint;
+ ProtocolChain: TWSAProtocolChain;
+ iVersion: integer;
+ iAddressFamily: integer;
+ iMaxSockAddr: integer;
+ iMinSockAddr: integer;
+ iSocketType: integer;
+ iProtocol: integer;
+ iProtocolMaxOffset: integer;
+ iNetworkByteOrder: integer;
+ iSecurityScheme: integer;
+ dwMessageSize: Longint;
+ dwProviderReserved: Longint;
+ szProtocol: array [0 .. WSAPROTOCOL_LEN + 1 - 1] of Char;
+ end { TWSAProtocol_InfoA };
+
+ PWSAProtocol_InfoA = ^TWSAProtocol_InfoA;
+ LPWSAProtocol_InfoA = PWSAProtocol_InfoA;
+
+ TWSAProtocol_InfoW = record
+ dwServiceFlags1: Longint;
+ dwServiceFlags2: Longint;
+ dwServiceFlags3: Longint;
+ dwServiceFlags4: Longint;
+ dwProviderFlags: Longint;
+ ProviderId: TGUID;
+ dwCatalogEntryId: Longint;
+ ProtocolChain: TWSAProtocolChain;
+ iVersion: integer;
+ iAddressFamily: integer;
+ iMaxSockAddr: integer;
+ iMinSockAddr: integer;
+ iSocketType: integer;
+ iProtocol: integer;
+ iProtocolMaxOffset: integer;
+ iNetworkByteOrder: integer;
+ iSecurityScheme: integer;
+ dwMessageSize: Longint;
+ dwProviderReserved: Longint;
+ szProtocol: array [0 .. WSAPROTOCOL_LEN + 1 - 1] of WideChar;
+ end { TWSAProtocol_InfoW };
+
+ PWSAProtocol_InfoW = ^TWSAProtocol_InfoW;
+ LPWSAProtocol_InfoW = PWSAProtocol_InfoW;
+
+{$IFDEF UNICODE}
+ WSAProtocol_Info = TWSAProtocol_InfoW;
+ TWSAProtocol_Info = TWSAProtocol_InfoW;
+ PWSAProtocol_Info = PWSAProtocol_InfoW;
+ LPWSAProtocol_Info = PWSAProtocol_InfoW;
+{$ELSE}
+ WSAProtocol_Info = TWSAProtocol_InfoA;
+ TWSAProtocol_Info = TWSAProtocol_InfoA;
+ PWSAProtocol_Info = PWSAProtocol_InfoA;
+ LPWSAProtocol_Info = PWSAProtocol_InfoA;
+{$ENDIF}
+
+
+const
+ // Flag bit definitions for dwProviderFlags
+ PFL_MULTIPLE_PROTO_ENTRIES = $00000001;
+ PFL_RECOMMENDED_PROTO_ENTRY = $00000002;
+ PFL_HIDDEN = $00000004;
+ PFL_MATCHES_PROTOCOL_ZERO = $00000008;
+
+ // Flag bit definitions for dwServiceFlags1
+ XP1_CONNECTIONLESS = $00000001;
+ XP1_GUARANTEED_DELIVERY = $00000002;
+ XP1_GUARANTEED_ORDER = $00000004;
+ XP1_MESSAGE_ORIENTED = $00000008;
+ XP1_PSEUDO_STREAM = $00000010;
+ XP1_GRACEFUL_CLOSE = $00000020;
+ XP1_EXPEDITED_DATA = $00000040;
+ XP1_CONNECT_DATA = $00000080;
+ XP1_DISCONNECT_DATA = $00000100;
+ XP1_SUPPORT_BROADCAST = $00000200;
+ XP1_SUPPORT_MULTIPOINT = $00000400;
+ XP1_MULTIPOINT_CONTROL_PLANE = $00000800;
+ XP1_MULTIPOINT_DATA_PLANE = $00001000;
+ XP1_QOS_SUPPORTED = $00002000;
+ XP1_INTERRUPT = $00004000;
+ XP1_UNI_SEND = $00008000;
+ XP1_UNI_RECV = $00010000;
+ XP1_IFS_HANDLES = $00020000;
+ XP1_PARTIAL_MESSAGE = $00040000;
+
+ BIGENDIAN = $0000;
+ LITTLEENDIAN = $0001;
+
+ SECURITY_PROTOCOL_NONE = $0000;
+
+ // WinSock 2 extension -- manifest constants for WSAJoinLeaf()
+ JL_SENDER_ONLY = $01;
+ JL_RECEIVER_ONLY = $02;
+ JL_BOTH = $04;
+
+ // WinSock 2 extension -- manifest constants for WSASocket()
+ WSA_FLAG_OVERLAPPED = $01;
+ WSA_FLAG_MULTIPOINT_C_ROOT = $02;
+ WSA_FLAG_MULTIPOINT_C_LEAF = $04;
+ WSA_FLAG_MULTIPOINT_D_ROOT = $08;
+ WSA_FLAG_MULTIPOINT_D_LEAF = $10;
+
+ // WinSock 2 extension -- manifest constants for WSAIoctl()
+ IOC_UNIX = $00000000;
+ IOC_WS2 = $08000000;
+ IOC_PROTOCOL = $10000000;
+ IOC_VENDOR = $18000000;
+
+ SIO_ASSOCIATE_HANDLE = 1 or IOC_WS2 or IOC_IN;
+ SIO_ENABLE_CIRCULAR_QUEUEING = 2 or IOC_WS2;
+ SIO_FIND_ROUTE = 3 or IOC_WS2 or IOC_OUT;
+ SIO_FLUSH = 4 or IOC_WS2;
+ SIO_GET_BROADCAST_ADDRESS = 5 or IOC_WS2 or IOC_OUT;
+ SIO_GET_EXTENSION_FUNCTION_POINTER = 6 or IOC_WS2 or IOC_INOUT;
+ SIO_GET_QOS = 7 or IOC_WS2 or IOC_INOUT;
+ SIO_GET_GROUP_QOS = 8 or IOC_WS2 or IOC_INOUT;
+ SIO_MULTIPOINT_LOOPBACK = 9 or IOC_WS2 or IOC_IN;
+ SIO_MULTICAST_SCOPE = 10 or IOC_WS2 or IOC_IN;
+ SIO_SET_QOS = 11 or IOC_WS2 or IOC_IN;
+ SIO_SET_GROUP_QOS = 12 or IOC_WS2 or IOC_IN;
+ SIO_TRANSLATE_HANDLE = 13 or IOC_WS2 or IOC_INOUT;
+ SIO_ROUTING_INTERFACE_QUERY = 20 or IOC_WS2 or IOC_INOUT;
+ SIO_ROUTING_INTERFACE_CHANGE = 21 or IOC_WS2 or IOC_IN;
+ SIO_ADDRESS_LIST_QUERY = 22 or IOC_WS2 or IOC_OUT; // see below SOCKET_ADDRESS_LIST
+ SIO_ADDRESS_LIST_CHANGE = 23 or IOC_WS2;
+ SIO_QUERY_TARGET_PNP_HANDLE = 24 or IOC_WS2 or IOC_OUT;
+
+ // WinSock 2 extension -- manifest constants for SIO_TRANSLATE_HANDLE ioctl
+ TH_NETDEV = $00000001;
+ TH_TAPI = $00000002;
+
+type
+
+ // Manifest constants and type definitions related to name resolution and
+ // registration (RNR) API
+ TBLOB = packed record
+ cbSize: u_long;
+ pBlobData: PBYTE;
+ end;
+
+ PBLOB = ^TBLOB;
+
+ // Service Install Flags
+
+const
+ SERVICE_MULTIPLE = $00000001;
+
+ // & Name Spaces
+ NS_ALL = 0;
+
+ NS_SAP = 1;
+ NS_NDS = 2;
+ NS_PEER_BROWSE = 3;
+
+ NS_TCPIP_LOCAL = 10;
+ NS_TCPIP_HOSTS = 11;
+ NS_DNS = 12;
+ NS_NETBT = 13;
+ NS_WINS = 14;
+
+ NS_NBP = 20;
+
+ NS_MS = 30;
+ NS_STDA = 31;
+ NS_NTDS = 32;
+
+ NS_X500 = 40;
+ NS_NIS = 41;
+ NS_NISPLUS = 42;
+
+ NS_WRQ = 50;
+
+ NS_NETDES = 60;
+
+ { Resolution flags for WSAGetAddressByName().
+ Note these are also used by the 1.1 API GetAddressByName, so leave them around. }
+ RES_UNUSED_1 = $00000001;
+ RES_FLUSH_CACHE = $00000002;
+ RES_SERVICE = $00000004;
+
+ { Well known value names for Service Types }
+ SERVICE_TYPE_VALUE_IPXPORTA = 'IpxSocket';
+ SERVICE_TYPE_VALUE_IPXPORTW: PWideChar = 'IpxSocket';
+
+{$IFDEF UNICODE}
+ SERVICE_TYPE_VALUE_SAPID: PWideChar = 'SapId';
+ SERVICE_TYPE_VALUE_TCPPORT: PWideChar = 'TcpPort';
+ SERVICE_TYPE_VALUE_UDPPORT: PWideChar = 'UdpPort';
+ SERVICE_TYPE_VALUE_OBJECTID: PWideChar = 'ObjectId';
+{$ELSE}
+ SERVICE_TYPE_VALUE_SAPID: PAnsiChar = 'SapId';
+ SERVICE_TYPE_VALUE_TCPPORT: PAnsiChar = 'TcpPort';
+ SERVICE_TYPE_VALUE_UDPPORT: PAnsiChar = 'UdpPort';
+ SERVICE_TYPE_VALUE_OBJECTID: PAnsiChar = 'ObjectId';
+{$ENDIF}
+
+ // SockAddr Information
+type
+ SOCKET_ADDRESS = packed record
+ lpSockaddr: PSockAddr;
+ iSockaddrLength: integer;
+ end;
+
+ PSOCKET_ADDRESS = ^SOCKET_ADDRESS;
+
+ // CSAddr Information
+ CSADDR_INFO = packed record
+ LocalAddr, RemoteAddr: SOCKET_ADDRESS;
+ iSocketType, iProtocol: Longint;
+ end;
+
+ PCSADDR_INFO = ^CSADDR_INFO;
+ LPCSADDR_INFO = ^CSADDR_INFO;
+
+
+ //
+ // Portable socket structure (RFC 2553).
+ //
+
+ //
+ // Desired design of maximum size and alignment.
+ // These are implementation specific.
+ //
+
+const
+ _SS_MAXSIZE = 128; // Maximum size.
+{$EXTERNALSYM _SS_MAXSIZE}
+ _SS_ALIGNSIZE = SizeOf(Int64); // Desired alignment.
+{$EXTERNALSYM _SS_ALIGNSIZE}
+
+ //
+ // Definitions used for sockaddr_storage structure paddings design.
+ //
+
+ _SS_PAD1SIZE = _SS_ALIGNSIZE - SizeOf(short);
+{$EXTERNALSYM _SS_PAD1SIZE}
+ _SS_PAD2SIZE = _SS_MAXSIZE - (SizeOf(short) + _SS_PAD1SIZE + _SS_ALIGNSIZE);
+{$EXTERNALSYM _SS_PAD2SIZE}
+
+
+type
+ sockaddr_storage = record
+ ss_family: short; // Address family.
+ __ss_pad1: array [0 .. _SS_PAD1SIZE - 1] of AnsiChar; // 6 byte pad, this is to make
+ // implementation specific pad up to
+ // alignment field that follows explicit
+ // in the data structure.
+ __ss_align: Int64; // Field to force desired structure.
+ __ss_pad2: array [0 .. _SS_PAD2SIZE - 1] of AnsiChar; // 112 byte pad to achieve desired size;
+ // _SS_MAXSIZE value minus size of
+ // ss_family, __ss_pad1, and
+ // __ss_align fields is 112.
+ end;
+{$EXTERNALSYM sockaddr_storage}
+
+ TSockAddrStorage = sockaddr_storage;
+ PSockAddrStorage = ^sockaddr_storage;
+
+ // Address list returned via WSAIoctl( SIO_ADDRESS_LIST_QUERY )
+ SOCKET_ADDRESS_LIST = packed record
+ iAddressCount: integer;
+ Address: array [0 .. 0] of SOCKET_ADDRESS;
+ end;
+
+ LPSOCKET_ADDRESS_LIST = ^SOCKET_ADDRESS_LIST;
+
+ // Address Family/Protocol Tuples
+ AFProtocols = record
+ iAddressFamily: integer;
+ iProtocol: integer;
+ end;
+
+ TAFProtocols = AFProtocols;
+ PAFProtocols = ^TAFProtocols;
+
+
+ // Client Query API Typedefs
+
+ // The comparators
+ TWSAEComparator = (COMP_EQUAL { = 0 } , COMP_NOTLESS);
+
+ TWSAVersion = record
+ dwVersion: DWORD;
+ ecHow: TWSAEComparator;
+ end;
+
+ PWSAVersion = ^TWSAVersion;
+
+ TWSAQuerySetA = packed record
+ dwSize: DWORD;
+ lpszServiceInstanceName: PAnsiChar;
+ lpServiceClassId: PGUID;
+ lpVersion: PWSAVersion;
+ lpszComment: PAnsiChar;
+ dwNameSpace: DWORD;
+ lpNSProviderId: PGUID;
+ lpszContext: PAnsiChar;
+ dwNumberOfProtocols: DWORD;
+ lpafpProtocols: PAFProtocols;
+ lpszQueryString: PAnsiChar;
+ dwNumberOfCsAddrs: DWORD;
+ lpcsaBuffer: PCSADDR_INFO;
+ dwOutputFlags: DWORD;
+ lpBlob: PBLOB;
+ end;
+
+ PWSAQuerySetA = ^TWSAQuerySetA;
+ LPWSAQuerySetA = PWSAQuerySetA;
+
+ TWSAQuerySetW = packed record
+ dwSize: DWORD;
+ lpszServiceInstanceName: PWideChar;
+ lpServiceClassId: PGUID;
+ lpVersion: PWSAVersion;
+ lpszComment: PWideChar;
+ dwNameSpace: DWORD;
+ lpNSProviderId: PGUID;
+ lpszContext: PWideChar;
+ dwNumberOfProtocols: DWORD;
+ lpafpProtocols: PAFProtocols;
+ lpszQueryString: PWideChar;
+ dwNumberOfCsAddrs: DWORD;
+ lpcsaBuffer: PCSADDR_INFO;
+ dwOutputFlags: DWORD;
+ lpBlob: PBLOB;
+ end;
+
+ PWSAQuerySetW = ^TWSAQuerySetW;
+ LPWSAQuerySetW = PWSAQuerySetW;
+
+{$IFDEF UNICODE}
+ TWSAQuerySet = TWSAQuerySetA;
+ PWSAQuerySet = PWSAQuerySetW;
+ LPWSAQuerySet = PWSAQuerySetW;
+{$ELSE}
+ TWSAQuerySet = TWSAQuerySetA;
+ PWSAQuerySet = PWSAQuerySetA;
+ LPWSAQuerySet = PWSAQuerySetA;
+{$ENDIF}
+
+
+const
+ LUP_DEEP = $0001;
+ LUP_CONTAINERS = $0002;
+ LUP_NOCONTAINERS = $0004;
+ LUP_NEAREST = $0008;
+ LUP_RETURN_NAME = $0010;
+ LUP_RETURN_TYPE = $0020;
+ LUP_RETURN_VERSION = $0040;
+ LUP_RETURN_COMMENT = $0080;
+ LUP_RETURN_ADDR = $0100;
+ LUP_RETURN_BLOB = $0200;
+ LUP_RETURN_ALIASES = $0400;
+ LUP_RETURN_QUERY_STRING = $0800;
+ LUP_RETURN_ALL = $0FF0;
+ LUP_RES_SERVICE = $8000;
+
+ LUP_FLUSHCACHE = $1000;
+ LUP_FLUSHPREVIOUS = $2000;
+
+ // Return flags
+ RESULT_IS_ALIAS = $0001;
+
+type
+ // Service Address Registration and Deregistration Data Types.
+ TWSAeSetServiceOp = (RNRSERVICE_REGISTER { =0 } , RNRSERVICE_DEREGISTER, RNRSERVICE_DELETE);
+
+ { Service Installation/Removal Data Types. }
+ TWSANSClassInfoA = packed record
+ lpszName: PAnsiChar;
+ dwNameSpace: DWORD;
+ dwValueType: DWORD;
+ dwValueSize: DWORD;
+ lpValue: pointer;
+ end;
+
+ PWSANSClassInfoA = ^TWSANSClassInfoA;
+
+ TWSANSClassInfoW = packed record
+ lpszName: PWideChar;
+ dwNameSpace: DWORD;
+ dwValueType: DWORD;
+ dwValueSize: DWORD;
+ lpValue: pointer;
+ end { TWSANSClassInfoW };
+
+ PWSANSClassInfoW = ^TWSANSClassInfoW;
+
+{$IFDEF UNICODE}
+ WSANSClassInfo = TWSANSClassInfoW;
+ TWSANSClassInfo = TWSANSClassInfoW;
+ PWSANSClassInfo = PWSANSClassInfoW;
+ LPWSANSClassInfo = PWSANSClassInfoW;
+{$ELSE}
+ WSANSClassInfo = TWSANSClassInfoA;
+ TWSANSClassInfo = TWSANSClassInfoA;
+ PWSANSClassInfo = PWSANSClassInfoA;
+ LPWSANSClassInfo = PWSANSClassInfoA;
+{$ENDIF // UNICODE}
+
+ TWSAServiceClassInfoA = packed record
+ lpServiceClassId: PGUID;
+ lpszServiceClassName: PAnsiChar;
+ dwCount: DWORD;
+ lpClassInfos: PWSANSClassInfoA;
+ end;
+
+ PWSAServiceClassInfoA = ^TWSAServiceClassInfoA;
+ LPWSAServiceClassInfoA = PWSAServiceClassInfoA;
+
+ TWSAServiceClassInfoW = packed record
+ lpServiceClassId: PGUID;
+ lpszServiceClassName: PWideChar;
+ dwCount: DWORD;
+ lpClassInfos: PWSANSClassInfoW;
+ end;
+
+ PWSAServiceClassInfoW = ^TWSAServiceClassInfoW;
+ LPWSAServiceClassInfoW = PWSAServiceClassInfoW;
+
+{$IFDEF UNICODE}
+ WSAServiceClassInfo = TWSAServiceClassInfoW;
+ TWSAServiceClassInfo = TWSAServiceClassInfoW;
+ PWSAServiceClassInfo = PWSAServiceClassInfoW;
+ LPWSAServiceClassInfo = PWSAServiceClassInfoW;
+{$ELSE}
+ WSAServiceClassInfo = TWSAServiceClassInfoA;
+ TWSAServiceClassInfo = TWSAServiceClassInfoA;
+ PWSAServiceClassInfo = PWSAServiceClassInfoA;
+ LPWSAServiceClassInfo = PWSAServiceClassInfoA;
+{$ENDIF}
+
+ TWSANameSpace_InfoA = packed record
+ NSProviderId: TGUID;
+ dwNameSpace: DWORD;
+ fActive: DWORD { Bool };
+ dwVersion: DWORD;
+ lpszIdentifier: PAnsiChar;
+ end;
+
+ PWSANameSpace_InfoA = ^TWSANameSpace_InfoA;
+ LPWSANameSpace_InfoA = PWSANameSpace_InfoA;
+
+ TWSANameSpace_InfoW = packed record
+ NSProviderId: TGUID;
+ dwNameSpace: DWORD;
+ fActive: DWORD { Bool };
+ dwVersion: DWORD;
+ lpszIdentifier: PWideChar;
+ end { TWSANameSpace_InfoW };
+
+ PWSANameSpace_InfoW = ^TWSANameSpace_InfoW;
+ LPWSANameSpace_InfoW = PWSANameSpace_InfoW;
+
+{$IFDEF UNICODE}
+ WSANameSpace_Info = TWSANameSpace_InfoW;
+ TWSANameSpace_Info = TWSANameSpace_InfoW;
+ PWSANameSpace_Info = PWSANameSpace_InfoW;
+ LPWSANameSpace_Info = PWSANameSpace_InfoW;
+{$ELSE}
+ WSANameSpace_Info = TWSANameSpace_InfoA;
+ TWSANameSpace_Info = TWSANameSpace_InfoA;
+ PWSANameSpace_Info = PWSANameSpace_InfoA;
+ LPWSANameSpace_Info = PWSANameSpace_InfoA;
+{$ENDIF}
+
+
+{ WinSock 2 extensions -- data types for the condition function in }
+{ WSAAccept() and overlapped I/O completion routine. }
+type
+ LPCONDITIONPROC = function(lpCallerId: LPWSABUF; lpCallerData: LPWSABUF; lpSQOS, lpGQOS: LPQOS; lpCalleeId, lpCalleeData: LPWSABUF; g: GROUP;
+ dwCallbackData: DWORD): integer; stdcall;
+
+ LPWSAOVERLAPPED_COMPLETION_ROUTINE = procedure(const dwError, cbTransferred: DWORD; const lpOverlapped: LPWSAOVERLAPPED; const dwFlags: DWORD); stdcall;
+
+ LPFN_CONNECTEX = function(s: TSocket; const SOCKADDR: PSockAddr; namelen: integer; lpSendBuffer: pointer; dwSendDataLength: DWORD; lpdwBytesSent: PDWORD;
+ lpOverlapped: POverlapped): BOOL; stdcall;
+
+ LPFN_ACCEPTEX = function(sListenSocket, sAcceptSocket: TSocket; lpOutputBuffer: LPVOID;
+ dwReceiveDataLength, dwLocalAddressLength, dwRemoteAddressLength: DWORD; var lpdwBytesReceived: DWORD; lpOverlapped: POverlapped): BOOL; stdcall;
+
+ LPFN_TRANSMITFILE = function(hSocket: TSocket; hFile: THandle; nNumberOfBytesToWrite: DWORD; nNumberOfBytesPerSend: DWORD; lpOverlapped: POverlapped;
+ lpTransmitBuffers: pointer; dwFlags: DWORD): BOOL; stdcall;
+
+ LPFN_GETACCEPTEXSOCKADDRS = procedure(lpOutputBuffer: LPVOID; dwReceiveDataLength, dwLocalAddressLength, dwRemoteAddressLength: DWORD;
+ var LocalSockaddr: PSockAddr; var LocalSockaddrLength: integer; var RemoteSockaddr: PSockAddr; var RemoteSockaddrLength: integer); stdcall;
+
+const
+
+ // Flags for getnameinfo()
+
+ NI_NOFQDN = $01; // Only return nodename portion for local hosts
+ NI_NUMERICHOST = $02; // Return numeric form of the host's address
+ NI_NAMEREQD = $04; // Error if the host's name not in DNS
+ NI_NUMERICSERV = $08; // Return numeric form of the service (port #)
+ NI_DGRAM = $10; // Service is a datagram service
+
+ NI_MAXHOST = 1025; // Max size of a fully-qualified domain name
+ NI_MAXSERV = 32; // Max size of a service name
+
+function accept(const s: TSocket; var addr: TSockAddr; var addrlen: integer): TSocket; stdcall;
+function bind(const s: TSocket; const addr: PSockAddr; const namelen: integer): integer; stdcall;
+function closesocket(const s: TSocket): integer; stdcall;
+function connect(const s: TSocket; const name: PSockAddr; namelen: integer): integer; stdcall;
+function ioctlsocket(const s: TSocket; const cmd: DWORD; var arg: u_long): integer; stdcall;
+function getpeername(const s: TSocket; var name: TSockAddr; var namelen: integer): integer; stdcall;
+function getsockname(const s: TSocket; var name: TSockAddr; var namelen: integer): integer; stdcall;
+function getsockopt(const s: TSocket; const level, optname: integer; optval: PAnsiChar; var optlen: integer): integer; stdcall;
+function htonl(hostlong: u_long): u_long; stdcall;
+function htons(hostshort: u_short): u_short; stdcall;
+function inet_addr(cp: PAnsiChar): u_long; stdcall;
+function inet_ntoa(inaddr: TInAddr): PAnsiChar; stdcall;
+function listen(s: TSocket; backlog: integer): integer; stdcall;
+function ntohl(netlong: u_long): u_long; stdcall;
+function ntohs(netshort: u_short): u_short; stdcall;
+function recv(s: TSocket; out buf; len, flags: integer): integer; stdcall;
+function recvfrom(s: TSocket; var buf; len, flags: integer; var from: TSockAddr; var fromlen: integer): integer; stdcall;
+function select(nfds: integer; readfds, writefds, exceptfds: PFDSet; timeout: PTimeVal): integer; stdcall;
+function send(s: TSocket; const buf; len, flags: integer): integer; stdcall;
+function sendto(s: TSocket; var buf; len, flags: integer; var addrto: TSockAddr; tolen: integer): integer; stdcall;
+function setsockopt(s: TSocket; level, optname: integer; optval: PAnsiChar; optlen: integer): integer; stdcall;
+function shutdown(s: TSocket; how: integer): integer; stdcall;
+function socket(const af, struct, protocol: integer): TSocket; stdcall;
+function gethostbyaddr(addr: pointer; len, struct: integer): PHostEnt; stdcall;
+function gethostbyname(name: PAnsiChar): PHostEnt; stdcall;
+function gethostname(name: PAnsiChar; len: integer): integer; stdcall;
+function getservbyport(port: integer; proto: PAnsiChar): PServEnt; stdcall;
+function getservbyname(const name, proto: PAnsiChar): PServEnt; stdcall;
+function getprotobynumber(const proto: integer): PProtoEnt; stdcall;
+function getprotobyname(const name: PAnsiChar): PProtoEnt; stdcall;
+function GetAddrInfo(const nodename, servname: PChar; const hints: PAddrInfo; res: PPAddrInfo): integer; stdcall;
+procedure FreeAddrInfo(ai: PAddrInfo); stdcall;
+function WSAStartup(wVersionRequired: Word; var WSData: TWSAData): integer; stdcall;
+function WSACleanup: integer; stdcall;
+procedure WSASetLastError(iError: integer); stdcall;
+function WSAGetLastError: integer; stdcall;
+function WSAIsBlocking: BOOL; stdcall;
+function WSAUnhookBlockingHook: integer; stdcall;
+function WSASetBlockingHook(lpBlockFunc: TFarProc): TFarProc; stdcall;
+function WSACancelBlockingCall: integer; stdcall;
+function WSAAsyncGetServByName(HWindow: HWND; wMsg: u_int; name, proto, buf: PAnsiChar; buflen: integer): THandle; stdcall;
+function WSAAsyncGetServByPort(HWindow: HWND; wMsg, port: u_int; proto, buf: PAnsiChar; buflen: integer): THandle; stdcall;
+function WSAAsyncGetProtoByName(HWindow: HWND; wMsg: u_int; name, buf: PAnsiChar; buflen: integer): THandle; stdcall;
+function WSAAsyncGetProtoByNumber(HWindow: HWND; wMsg: u_int; number: integer; buf: PAnsiChar; buflen: integer): THandle; stdcall;
+function WSAAsyncGetHostByName(HWindow: HWND; wMsg: u_int; name, buf: PAnsiChar; buflen: integer): THandle; stdcall;
+function WSAAsyncGetHostByAddr(HWindow: HWND; wMsg: u_int; addr: PAnsiChar; len, struct: integer; buf: PAnsiChar; buflen: integer): THandle; stdcall;
+function WSACancelAsyncRequest(hAsyncTaskHandle: THandle): integer; stdcall;
+function WSAAsyncSelect(s: TSocket; HWindow: HWND; wMsg: u_int; lEvent: Longint): integer; stdcall;
+function __WSAFDIsSet(s: TSocket; var FDSet: TFDSet): BOOL; stdcall;
+
+{ WinSock 2 API new function prototypes }
+function WSAAccept(s: TSocket; addr: TSockAddr; addrlen: PInteger; lpfnCondition: LPCONDITIONPROC; dwCallbackData: DWORD): TSocket; stdcall;
+function WSACloseEvent(hEvent: WSAEVENT): WordBool; stdcall;
+function WSAConnect(s: TSocket; const name: PSockAddr; namelen: integer; lpCallerData, lpCalleeData: LPWSABUF; lpSQOS, lpGQOS: LPQOS): integer; stdcall;
+function WSACreateEvent: WSAEVENT; stdcall;
+
+function WSADuplicateSocketA(s: TSocket; dwProcessId: DWORD; lpProtocolInfo: LPWSAProtocol_InfoA): integer; stdcall;
+function WSADuplicateSocketW(s: TSocket; dwProcessId: DWORD; lpProtocolInfo: LPWSAProtocol_InfoW): integer; stdcall;
+function WSADuplicateSocket(s: TSocket; dwProcessId: DWORD; lpProtocolInfo: LPWSAProtocol_Info): integer; stdcall;
+
+function WSAEnumNetworkEvents(const s: TSocket; const hEventObject: WSAEVENT; lpNetworkEvents: LPWSANetworkEvents): integer; stdcall;
+function WSAEnumProtocolsA(lpiProtocols: PInteger; lpProtocolBuffer: LPWSAProtocol_InfoA; var lpdwBufferLength: DWORD): integer; stdcall;
+function WSAEnumProtocolsW(lpiProtocols: PInteger; lpProtocolBuffer: LPWSAProtocol_InfoW; var lpdwBufferLength: DWORD): integer; stdcall;
+function WSAEnumProtocols(lpiProtocols: PInteger; lpProtocolBuffer: LPWSAProtocol_Info; var lpdwBufferLength: DWORD): integer; stdcall;
+
+function WSAEventSelect(s: TSocket; hEventObject: WSAEVENT; lNetworkEvents: Longint): integer; stdcall;
+
+function WSAGetOverlappedResult(s: TSocket; lpOverlapped: LPWSAOVERLAPPED; lpcbTransfer: LPDWORD; fWait: BOOL; var lpdwFlags: DWORD): WordBool; stdcall;
+
+function WSAGetQosByName(s: TSocket; lpQOSName: LPWSABUF; LPQOS: LPQOS): WordBool; stdcall;
+
+function WSAhtonl(s: TSocket; hostlong: u_long; var lpnetlong: DWORD): integer; stdcall;
+function WSAhtons(s: TSocket; hostshort: u_short; var lpnetshort: Word): integer; stdcall;
+
+function WSAIoctl(s: TSocket; dwIoControlCode: DWORD; lpvInBuffer: pointer; cbInBuffer: DWORD; lpvOutBuffer: pointer; cbOutBuffer: DWORD;
+ lpcbBytesReturned: LPDWORD; lpOverlapped: LPWSAOVERLAPPED; lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE): integer; stdcall;
+
+function WSAJoinLeaf(s: TSocket; name: PSockAddr; namelen: integer; lpCallerData, lpCalleeData: LPWSABUF; lpSQOS, lpGQOS: LPQOS; dwFlags: DWORD)
+ : TSocket; stdcall;
+
+function WSANtohl(s: TSocket; netlong: u_long; var lphostlong: DWORD): integer; stdcall;
+function WSANtohs(s: TSocket; netshort: u_short; var lphostshort: Word): integer; stdcall;
+
+function WSARecv(s: TSocket; lpBuffers: LPWSABUF; dwBufferCount: DWORD; var lpNumberOfBytesRecvd: DWORD; var lpFlags: DWORD; lpOverlapped: LPWSAOVERLAPPED;
+ lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE): integer; stdcall;
+function WSARecvDisconnect(s: TSocket; lpInboundDisconnectData: LPWSABUF): integer; stdcall;
+function WSARecvFrom(s: TSocket; lpBuffers: LPWSABUF; dwBufferCount: DWORD; var lpNumberOfBytesRecvd: DWORD; var lpFlags: DWORD; lpFrom: PSockAddr;
+ lpFromlen: PInteger; lpOverlapped: LPWSAOVERLAPPED; lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE): integer; stdcall;
+
+function WSAResetEvent(hEvent: WSAEVENT): WordBool; stdcall;
+
+function WSASend(s: TSocket; lpBuffers: LPWSABUF; dwBufferCount: DWORD; var lpNumberOfBytesSent: DWORD; dwFlags: DWORD; lpOverlapped: LPWSAOVERLAPPED;
+ lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE): integer; stdcall;
+function WSASendDisconnect(s: TSocket; lpOutboundDisconnectData: LPWSABUF): integer; stdcall;
+function WSASendTo(s: TSocket; lpBuffers: LPWSABUF; dwBufferCount: DWORD; var lpNumberOfBytesSent: DWORD; dwFlags: DWORD; lpTo: PSockAddr; iTolen: integer;
+ lpOverlapped: LPWSAOVERLAPPED; lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE): integer; stdcall;
+
+function WSASetEvent(hEvent: WSAEVENT): WordBool; stdcall;
+
+function WSASocketA(af, iType, protocol: integer; lpProtocolInfo: LPWSAProtocol_InfoA; g: GROUP; dwFlags: DWORD): TSocket; stdcall;
+function WSASocketW(af, iType, protocol: integer; lpProtocolInfo: LPWSAProtocol_InfoW; g: GROUP; dwFlags: DWORD): TSocket; stdcall;
+function WSASocket(af, iType, protocol: integer; lpProtocolInfo: LPWSAProtocol_Info; g: GROUP; dwFlags: DWORD): TSocket; stdcall;
+
+function WSAWaitForMultipleEvents(cEvents: DWORD; lphEvents: PWSAEVENT; fWaitAll: LongBool; dwTimeout: DWORD; fAlertable: LongBool): DWORD; stdcall;
+
+function WSAAddressToStringA(lpsaAddress: PSockAddr; const dwAddressLength: DWORD; const lpProtocolInfo: LPWSAProtocol_InfoA; const lpszAddressString: PAnsiChar;
+ var lpdwAddressStringLength: DWORD): integer; stdcall;
+function WSAAddressToStringW(lpsaAddress: PSockAddr; const dwAddressLength: DWORD; const lpProtocolInfo: LPWSAProtocol_InfoW;
+ const lpszAddressString: PWideChar; var lpdwAddressStringLength: DWORD): integer; stdcall;
+function WSAAddressToString(lpsaAddress: PSockAddr; const dwAddressLength: DWORD; const lpProtocolInfo: LPWSAProtocol_Info; const lpszAddressString: PMBChar;
+ var lpdwAddressStringLength: DWORD): integer; stdcall;
+
+function WSAStringToAddressA(const AddressString: PAnsiChar; const AddressFamily: integer; const lpProtocolInfo: LPWSAProtocol_InfoA; var lpAddress: TSockAddr;
+ var lpAddressLength: integer): integer; stdcall;
+function WSAStringToAddressW(const AddressString: PWideChar; const AddressFamily: integer; const lpProtocolInfo: LPWSAProtocol_InfoA; var lpAddress: TSockAddr;
+ var lpAddressLength: integer): integer; stdcall;
+function WSAStringToAddress(const AddressString: PMBChar; const AddressFamily: integer; const lpProtocolInfo: LPWSAProtocol_Info; var lpAddress: TSockAddr;
+ var lpAddressLength: integer): integer; stdcall;
+
+{ Registration and Name Resolution API functions }
+function WSALookupServiceBeginA(var qsRestrictions: TWSAQuerySetA; const dwControlFlags: DWORD; var hLookup: THandle): integer; stdcall;
+function WSALookupServiceBeginW(var qsRestrictions: TWSAQuerySetW; const dwControlFlags: DWORD; var hLookup: THandle): integer; stdcall;
+function WSALookupServiceBegin(var qsRestrictions: TWSAQuerySet; const dwControlFlags: DWORD; var hLookup: THandle): integer; stdcall;
+
+function WSALookupServiceNextA(const hLookup: THandle; const dwControlFlags: DWORD; var dwBufferLength: DWORD; lpqsResults: PWSAQuerySetA): integer; stdcall;
+function WSALookupServiceNextW(const hLookup: THandle; const dwControlFlags: DWORD; var dwBufferLength: DWORD; lpqsResults: PWSAQuerySetW): integer; stdcall;
+function WSALookupServiceNext(const hLookup: THandle; const dwControlFlags: DWORD; var dwBufferLength: DWORD; lpqsResults: PWSAQuerySet): integer; stdcall;
+
+function WSALookupServiceEnd(const hLookup: THandle): integer; stdcall;
+
+function WSAInstallServiceClassA(const lpServiceClassInfo: LPWSAServiceClassInfoA): integer; stdcall;
+function WSAInstallServiceClassW(const lpServiceClassInfo: LPWSAServiceClassInfoW): integer; stdcall;
+function WSAInstallServiceClass(const lpServiceClassInfo: LPWSAServiceClassInfo): integer; stdcall;
+
+function WSARemoveServiceClass(const lpServiceClassId: PGUID): integer; stdcall;
+
+function WSAGetServiceClassInfoA(const lpProviderId: PGUID; const lpServiceClassId: PGUID; var lpdwBufSize: DWORD; lpServiceClassInfo: LPWSAServiceClassInfoA)
+ : integer; stdcall;
+function WSAGetServiceClassInfoW(const lpProviderId: PGUID; const lpServiceClassId: PGUID; var lpdwBufSize: DWORD; lpServiceClassInfo: LPWSAServiceClassInfoW)
+ : integer; stdcall;
+function WSAGetServiceClassInfo(const lpProviderId: PGUID; const lpServiceClassId: PGUID; var lpdwBufSize: DWORD; lpServiceClassInfo: LPWSAServiceClassInfo)
+ : integer; stdcall;
+
+function WSAEnumNameSpaceProvidersA(var lpdwBufferLength: DWORD; const lpnspBuffer: LPWSANameSpace_InfoA): integer; stdcall;
+function WSAEnumNameSpaceProvidersW(var lpdwBufferLength: DWORD; const lpnspBuffer: LPWSANameSpace_InfoW): integer; stdcall;
+function WSAEnumNameSpaceProviders(var lpdwBufferLength: DWORD; const lpnspBuffer: LPWSANameSpace_Info): integer; stdcall;
+
+function WSAGetServiceClassNameByClassIdA(const lpServiceClassId: PGUID; lpszServiceClassName: PAnsiChar; var lpdwBufferLength: DWORD): integer; stdcall;
+function WSAGetServiceClassNameByClassIdW(const lpServiceClassId: PGUID; lpszServiceClassName: PWideChar; var lpdwBufferLength: DWORD): integer; stdcall;
+function WSAGetServiceClassNameByClassId(const lpServiceClassId: PGUID; lpszServiceClassName: PMBChar; var lpdwBufferLength: DWORD): integer; stdcall;
+
+function WSASetServiceA(const lpqsRegInfo: LPWSAQuerySetA; const essoperation: TWSAeSetServiceOp; const dwControlFlags: DWORD): integer; stdcall;
+function WSASetServiceW(const lpqsRegInfo: LPWSAQuerySetW; const essoperation: TWSAeSetServiceOp; const dwControlFlags: DWORD): integer; stdcall;
+function WSASetService(const lpqsRegInfo: LPWSAQuerySet; const essoperation: TWSAeSetServiceOp; const dwControlFlags: DWORD): integer; stdcall;
+
+function WSAProviderConfigChange(var lpNotificationHandle: THandle; lpOverlapped: LPWSAOVERLAPPED; lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE)
+ : integer; stdcall;
+
+function getnameinfo(const pAddr: pointer; addrlen: socklen_t; host: PAnsiChar; hostlen: DWORD; serv: PAnsiChar; servlen: DWORD; flags: integer): integer; stdcall;
+function GetNameInfoW(const pAddr: pointer; addrlen: socklen_t; host: PWideChar; hostlen: DWORD; serv: PWideChar; servlen: DWORD; flags: integer): integer; stdcall;
+
+{ Macros }
+function WSAMakeSyncReply(buflen, Error: Word): Longint;
+function WSAMakeSelectReply(Event, Error: Word): Longint;
+function WSAGetAsyncBuflen(aParam: Longint): Word;
+function WSAGetAsyncError(aParam: Longint): Word;
+function WSAGetSelectEvent(aParam: Longint): Word;
+function WSAGetSelectError(aParam: Longint): Word;
+
+procedure FD_CLR(socket: TSocket; var FDSet: TFDSet);
+function FD_ISSET(socket: TSocket; var FDSet: TFDSet): Boolean;
+procedure FD_SET(socket: TSocket; var FDSet: TFDSet);
+procedure FD_ZERO(var FDSet: TFDSet);
+
+{ Extension functions }
+
+var
+ ConnectEx: LPFN_CONNECTEX;
+
+function LoadConnectEx(const aSocket: TSocket): integer;
+
+{ ============================================================ }
+{ ======================= Custom Types ======================= }
+{ ============================================================ }
+
+const
+ { Socks version }
+ SOCKSVER4 = $04;
+ SOCKSVER5 = $05;
+
+ { Socks commands }
+ SOCKSCMD_TCPCONNECT = $01; // RFC 1928
+ SOCKSCMD_TCPBIND = $02; // RFC 1928
+ SOCKSCMD_UDPASSOC = $03; // RFC 1928
+ SOCKSCMD_RESOLVE = $F0; // Tor extension
+ SOCKSCMD_RESOLVEPTR = $F1; // Tor extension
+
+ { Socks5 authentication methods }
+ SOCKS5AUTH_NOAUTH = 0;
+ SOCKS5AUTH_GSSAPI = 1;
+ SOCKS5AUTH_USERPASS = 2;
+
+ { Socks address types }
+ SOCKSADDRTYP_IPV4 = $01;
+ SOCKSADDRTYP_DOMAINNAME = $03;
+ SOCKSADDRTYP_IPV6 = $04;
+
+type
+ { TIPProtocol }
+ { IP protocol in an enum form. }
+ TIPProtocol = (
+ ptIP = IPPROTO_IP,
+ ptICMP = IPPROTO_ICMP,
+ ptIGMP = IPPROTO_IGMP,
+ ptGGP = IPPROTO_GGP,
+ ptTCP = IPPROTO_TCP,
+ ptPUP = IPPROTO_PUP,
+ ptUDP = IPPROTO_UDP,
+ ptIDP = IPPROTO_IDP,
+ ptND = IPPROTO_ND,
+ ptRAW = IPPROTO_RAW
+ );
+
+ { TSocketType }
+ { Socket type in an enum form. }
+ TSocketType = (
+ stStream = SOCK_STREAM,
+ stDGram = SOCK_DGRAM,
+ stRaw = SOCK_RAW,
+ stRDM = SOCK_RDM,
+ stSeqpacket = SOCK_SEQPACKET
+ );
+
+ { TAddressFamily }
+ { IP address family in an enum form. }
+ TAddressFamily = (afUnspec = AF_UNSPEC, afIPv4 = AF_INET, afIPv6 = AF_INET6);
+ TAddressFamilies = set of TAddressFamily;
+
+ { TProxyType }
+ { Proxy protocol type/version. }
+ TProxyType = (ptNone, ptHTTP, ptSocks4, ptSocks5);
+ TProxyTypes = set of TProxyType;
+
+ { TTCPState }
+ { Indicates the state of a TCP connection. }
+ TTCPState = (
+ tsClosed, tsListening, tsSynSent, tsSynReceived, tsEstablished, tsFinWait1, tsFinWait2, tsCloseWait,
+ tsClosing, tsLastAck, tsTimeWait, tsDeleteTCB
+ );
+
+{ ============================================================ }
+{ ==================== Helper functions ====================== }
+{ ============================================================ }
+
+function InitWinsock: Boolean;
+procedure FinWinsock;
+
+{ Error functions }
+function GetWinsockErrorText(const aError: integer): string;
+function GetLastWinsockErrorText: string;
+
+{ Quick utils for testing, mostly. }
+function CreateTcpSock(const aAf: TAddressFamily = afIPv4): TSocket;
+function CreateUdpSock(const aAf: TAddressFamily = afIPv4): TSocket;
+function CreateRawSock(const aAf: TAddressFamily = afIPv4): TSocket;
+
+function ConnectTCPSock(const aSock: TSocket; const aAddrPool: PAddrInfo): Boolean;
+function ConnectTCPSockNonBlocking(const aSock: TSocket; const aAddrPool: PAddrInfo): Boolean;
+
+function MakeTcpConnection(const aHost, aPort: string; const aAf: TAddressFamily = afIPv4): TSocket;
+function MakeTcpConnectionSocks5(const aHost, aPort, aProxyHost, aProxyPort, aProxyUser, aProxyPass: string; const aAf: TAddressFamily = afIPv4): TSocket;
+
+function SendStrTcp(const aSock: TSocket; const aString: string): integer;
+function RecvStrTcp(const aSock: TSocket; var aString: string): integer;
+function RecvStrTcpNonBlocking(const aSock: TSocket; var aString: string): integer;
+
+procedure DeleteSock(var aSock: TSocket);
+
+{ Resolving utils }
+function GetAddrPool(
+ const aHost, aPort: string;
+ var aAddrInfo: PAddrInfo;
+ const aAf: TAddressFamily = afIPv4;
+ const aSockType: TSocketType = stStream;
+ const aProtocol: TIPProtocol = ptTCP;
+ const aFlags: integer = 0
+ ): integer;
+procedure FreeAddrPool(var aAddrInfo: PAddrInfo);
+
+{ Proxy handshakes }
+function GetSocks4ErrorText(const aErr: integer): string;
+function GetSocks5ErrorText(const aErr: integer): string;
+
+function NegotiateProxy(const aSocket: TSocket; const aHost, aPort, aUser: string): integer;
+function NegotiateSocks4(const aSocket: TSocket; const aHost, aPort, aUser, aPass: string): integer;
+function NegotiateSocks5(const aSocket: TSocket; const aHost, aPort, aUser, aPass: string): integer;
+
+{ Address conversion }
+function SockAddrToStr(const aSockAddr: PSockAddr; const aAddrLen: integer; var aOutString: string): Boolean; overload;
+function SockAddrToStr(const aSockAddr: PSockAddr; const aAddrLen: integer): string; overload;
+function ServToPortNum(const aServName: string; var aPort: Word): Boolean;
+
+function InAddr4ToStr(const aAddr: in_addr): string;
+function InAddr6ToStr(const aAddr: in6_addr; const aAbbreviate: boolean = True): string;
+function InAddr4RevLookup(const aAddr: in_addr; const aDGram: boolean = False): string;
+function InAddr6RevLookup(const aAddr: in6_addr; const aDGram: boolean = False): string;
+
+{ String conversion }
+function ProxyTypeToString(const aProxyType: TProxyType): string;
+function ProxyTypeToScheme(const aProxyType: TProxyType): string;
+
+{ ============================================================ }
+{ ====================== Helper types ======================== }
+{ ============================================================ }
+
+type
+
+ { GetAddrPoolAsync }
+ { Resolves an address asynchronously by using GetAddrInfo in a thread. }
+ { If you use more of these be sure to set IsMultiThreaded RTL var to true. }
+
+ { TGetAddrPoolAsyncData events. }
+ TOnResolved = reference to procedure(const aAddrPool: PAddrInfo; const aError: integer);
+
+ { GetAddrPoolAsync data }
+ TGetAddrPoolAsyncData = record
+ private
+ ThreadHandle: THandle;
+ class function GetAddrPoolAsyncThread(aParam: pointer): DWORD; stdcall; static;
+ public
+ host : string;
+ port : string;
+ AddressFamily: TAddressFamily;
+ SocketType : TSocketType;
+ Flags : integer;
+ OnResolved : TOnResolved;
+ procedure Initialize;
+ procedure Abort;
+ function Running: boolean;
+ end;
+
+ PGetAddrPoolAsyncData = ^TGetAddrPoolAsyncData;
+
+procedure GetAddrPoolAsync(var aData: TGetAddrPoolAsyncData);
+
+implementation
+
+uses
+ EvilWorks.System.StrUtils;
+
+function LoadConnectEx(const aSocket: TSocket): integer;
+var
+ guidConnectEx: System.TGUID;
+ Bytes : DWORD;
+begin
+ guidConnectEx := WSAID_CONNECTEX;
+ Result := WSAIoctl(aSocket, SIO_GET_EXTENSION_FUNCTION_POINTER, @guidConnectEx, SizeOf(guidConnectEx),
+ @@ConnectEx, SizeOf(@ConnectEx), @Bytes, nil, nil
+ );
+end;
+
+function accept; external WINSOCK2_DLL name 'accept';
+function bind; external WINSOCK2_DLL name 'bind';
+function closesocket; external WINSOCK2_DLL name 'closesocket';
+function connect; external WINSOCK2_DLL name 'connect';
+function ioctlsocket; external WINSOCK2_DLL name 'ioctlsocket';
+function getpeername; external WINSOCK2_DLL name 'getpeername';
+function getsockname; external WINSOCK2_DLL name 'getsockname';
+function getsockopt; external WINSOCK2_DLL name 'getsockopt';
+function htonl; external WINSOCK2_DLL name 'htonl';
+function htons; external WINSOCK2_DLL name 'htons';
+function inet_addr; external WINSOCK2_DLL name 'inet_addr';
+function inet_ntoa; external WINSOCK2_DLL name 'inet_ntoa';
+function listen; external WINSOCK2_DLL name 'listen';
+function ntohl; external WINSOCK2_DLL name 'ntohl';
+function ntohs; external WINSOCK2_DLL name 'ntohs';
+function recv; external WINSOCK2_DLL name 'recv';
+function recvfrom; external WINSOCK2_DLL name 'recvfrom';
+function select; external WINSOCK2_DLL name 'select';
+function send; external WINSOCK2_DLL name 'send';
+function sendto; external WINSOCK2_DLL name 'sendto';
+function setsockopt; external WINSOCK2_DLL name 'setsockopt';
+function shutdown; external WINSOCK2_DLL name 'shutdown';
+function socket; external WINSOCK2_DLL name 'socket';
+function gethostbyaddr; external WINSOCK2_DLL name 'gethostbyaddr';
+function gethostbyname; external WINSOCK2_DLL name 'gethostbyname';
+function gethostname; external WINSOCK2_DLL name 'gethostname';
+function getservbyport; external WINSOCK2_DLL name 'getservbyport';
+function getservbyname; external WINSOCK2_DLL name 'getservbyname';
+function getprotobynumber; external WINSOCK2_DLL name 'getprotobynumber';
+function getprotobyname; external WINSOCK2_DLL name 'getprotobyname';
+function WSAStartup; external WINSOCK2_DLL name 'WSAStartup';
+function WSACleanup; external WINSOCK2_DLL name 'WSACleanup';
+procedure WSASetLastError; external WINSOCK2_DLL name 'WSASetLastError';
+function WSAGetLastError; external WINSOCK2_DLL name 'WSAGetLastError';
+function WSAIsBlocking; external WINSOCK2_DLL name 'WSAIsBlocking';
+function WSAUnhookBlockingHook; external WINSOCK2_DLL name 'WSAUnhookBlockingHook';
+function WSASetBlockingHook; external WINSOCK2_DLL name 'WSASetBlockingHook';
+function WSACancelBlockingCall; external WINSOCK2_DLL name 'WSACancelBlockingCall';
+function WSAAsyncGetServByName; external WINSOCK2_DLL name 'WSAAsyncGetServByName';
+function WSAAsyncGetServByPort; external WINSOCK2_DLL name 'WSAAsyncGetServByPort';
+function WSAAsyncGetProtoByName; external WINSOCK2_DLL name 'WSAAsyncGetProtoByName';
+function WSAAsyncGetProtoByNumber; external WINSOCK2_DLL name 'WSAAsyncGetProtoByNumber';
+function WSAAsyncGetHostByName; external WINSOCK2_DLL name 'WSAAsyncGetHostByName';
+function WSAAsyncGetHostByAddr; external WINSOCK2_DLL name 'WSAAsyncGetHostByAddr';
+function WSACancelAsyncRequest; external WINSOCK2_DLL name 'WSACancelAsyncRequest';
+function WSAAsyncSelect; external WINSOCK2_DLL name 'WSAAsyncSelect';
+function __WSAFDIsSet; external WINSOCK2_DLL name '__WSAFDIsSet';
+
+{ WinSock 2 API new function prototypes }
+function WSAAccept; external WINSOCK2_DLL name 'WSAAccept';
+function WSACloseEvent; external WINSOCK2_DLL name 'WSACloseEvent';
+function WSAConnect; external WINSOCK2_DLL name 'WSAConnect';
+function WSACreateEvent; external WINSOCK2_DLL name 'WSACreateEvent';
+function WSADuplicateSocketA; external WINSOCK2_DLL name 'WSADuplicateSocketA';
+function WSADuplicateSocketW; external WINSOCK2_DLL name 'WSADuplicateSocketW';
+function WSAEnumNetworkEvents; external WINSOCK2_DLL name 'WSAEnumNetworkEvents';
+function WSAEnumProtocolsA; external WINSOCK2_DLL name 'WSAEnumProtocolsA';
+function WSAEnumProtocolsW; external WINSOCK2_DLL name 'WSAEnumProtocolsW';
+function WSAEventSelect; external WINSOCK2_DLL name 'WSAEventSelect';
+function WSAGetOverlappedResult; external WINSOCK2_DLL name 'WSAGetOverlappedResult';
+function WSAGetQosByName; external WINSOCK2_DLL name 'WSAGetQosByName';
+function WSAhtonl; external WINSOCK2_DLL name 'WSAhtonl';
+function WSAhtons; external WINSOCK2_DLL name 'WSAhtons';
+function WSAIoctl; external WINSOCK2_DLL name 'WSAIoctl';
+function WSAJoinLeaf; external WINSOCK2_DLL name 'WSAJoinLeaf';
+function WSANtohl; external WINSOCK2_DLL name 'WSANtohl';
+function WSANtohs; external WINSOCK2_DLL name 'WSANtohs';
+function WSARecv; external WINSOCK2_DLL name 'WSARecv';
+function WSARecvDisconnect; external WINSOCK2_DLL name 'WSARecvDisconnect';
+function WSARecvFrom; external WINSOCK2_DLL name 'WSARecvFrom';
+function WSAResetEvent; external WINSOCK2_DLL name 'WSAResetEvent';
+function WSASend; external WINSOCK2_DLL name 'WSASend';
+function WSASendDisconnect; external WINSOCK2_DLL name 'WSASendDisconnect';
+function WSASendTo; external WINSOCK2_DLL name 'WSASendTo';
+function WSASetEvent; external WINSOCK2_DLL name 'WSASetEvent';
+function WSASocketA; external WINSOCK2_DLL name 'WSASocketA';
+function WSASocketW; external WINSOCK2_DLL name 'WSASocketW';
+function WSAWaitForMultipleEvents; external WINSOCK2_DLL name 'WSAWaitForMultipleEvents';
+function WSAAddressToStringA; external WINSOCK2_DLL name 'WSAAddressToStringA';
+function WSAAddressToStringW; external WINSOCK2_DLL name 'WSAAddressToStringW';
+function WSAStringToAddressA; external WINSOCK2_DLL name 'WSAStringToAddressA';
+function WSAStringToAddressW; external WINSOCK2_DLL name 'WSAStringToAddressW';
+
+{ Registration and Name Resolution API functions }
+function WSALookupServiceBeginA; external WINSOCK2_DLL name 'WSALookupServiceBeginA';
+function WSALookupServiceBeginW; external WINSOCK2_DLL name 'WSALookupServiceBeginW';
+function WSALookupServiceNextA; external WINSOCK2_DLL name 'WSALookupServiceNextA';
+function WSALookupServiceNextW; external WINSOCK2_DLL name 'WSALookupServiceNextW';
+function WSALookupServiceEnd; external WINSOCK2_DLL name 'WSALookupServiceEnd';
+function WSAInstallServiceClassA; external WINSOCK2_DLL name 'WSAInstallServiceClassA';
+function WSAInstallServiceClassW; external WINSOCK2_DLL name 'WSAInstallServiceClassW';
+function WSARemoveServiceClass; external WINSOCK2_DLL name 'WSARemoveServiceClass';
+function WSAGetServiceClassInfoA; external WINSOCK2_DLL name 'WSAGetServiceClassInfoA';
+function WSAGetServiceClassInfoW; external WINSOCK2_DLL name 'WSAGetServiceClassInfoW';
+function WSAEnumNameSpaceProvidersA; external WINSOCK2_DLL name 'WSAEnumNameSpaceProvidersA';
+function WSAEnumNameSpaceProvidersW; external WINSOCK2_DLL name 'WSAEnumNameSpaceProvidersW';
+function WSAGetServiceClassNameByClassIdA; external WINSOCK2_DLL name 'WSAGetServiceClassNameByClassIdA';
+function WSAGetServiceClassNameByClassIdW; external WINSOCK2_DLL name 'WSAGetServiceClassNameByClassIdW';
+function WSASetServiceA; external WINSOCK2_DLL name 'WSASetServiceA';
+function WSASetServiceW; external WINSOCK2_DLL name 'WSASetServiceW';
+function WSAProviderConfigChange; external WINSOCK2_DLL name 'WSAProviderConfigChange';
+function getnameinfo; external WINSOCK2_DLL name 'getnameinfo';
+function GetNameInfoW; external WINSOCK2_DLL name 'GetNameInfoW';
+
+{$IFDEF UNICODE}
+function WSADuplicateSocket; external WINSOCK2_DLL name 'WSADuplicateSocketW';
+function WSAEnumProtocols; external WINSOCK2_DLL name 'WSAEnumProtocolsW';
+function WSASocket; external WINSOCK2_DLL name 'WSASocketW';
+function WSAAddressToString; external WINSOCK2_DLL name 'WSAAddressToStringW';
+function WSAStringToAddress; external WINSOCK2_DLL name 'WSAStringToAddressW';
+function WSALookupServiceBegin; external WINSOCK2_DLL name 'WSALookupServiceBeginW';
+function WSALookupServiceNext; external WINSOCK2_DLL name 'WSALookupServiceNextW';
+function WSAInstallServiceClass; external WINSOCK2_DLL name 'WSAInstallServiceClassW';
+function WSAGetServiceClassInfo; external WINSOCK2_DLL name 'WSAGetServiceClassInfoW';
+function WSAEnumNameSpaceProviders; external WINSOCK2_DLL name 'WSAEnumNameSpaceProvidersW';
+function WSAGetServiceClassNameByClassId; external WINSOCK2_DLL name 'WSAGetServiceClassNameByClassIdW';
+function WSASetService; external WINSOCK2_DLL name 'WSASetServiceW';
+function GetAddrInfo; external WINSOCK2_DLL name 'GetAddrInfoW';
+procedure FreeAddrInfo; external WINSOCK2_DLL name 'FreeAddrInfoW';
+{$ELSE}
+function WSADuplicateSocket; external WINSOCK2_DLL name 'WSADuplicateSocketA';
+function WSAEnumProtocols; external WINSOCK2_DLL name 'WSAEnumProtocolsA';
+function WSASocket; external WINSOCK2_DLL name 'WSASocketA';
+function WSAAddressToString; external WINSOCK2_DLL name 'WSAAddressToStringA';
+function WSAStringToAddress; external WINSOCK2_DLL name 'WSAStringToAddressA';
+function WSALookupServiceBegin; external WINSOCK2_DLL name 'WSALookupServiceBeginA';
+function WSALookupServiceNext; external WINSOCK2_DLL name 'WSALookupServiceNextA';
+function WSAInstallServiceClass; external WINSOCK2_DLL name 'WSAInstallServiceClassA';
+function WSAGetServiceClassInfo; external WINSOCK2_DLL name 'WSAGetServiceClassInfoA';
+function WSAEnumNameSpaceProviders; external WINSOCK2_DLL name 'WSAEnumNameSpaceProvidersA';
+function WSAGetServiceClassNameByClassId; external WINSOCK2_DLL name 'WSAGetServiceClassNameByClassIdA';
+function WSASetService; external WINSOCK2_DLL name 'WSASetServiceA';
+function GetAddrInfo; external WINSOCK2_DLL name 'GetAddrInfoA';
+procedure FreeAddrInfo; external WINSOCK2_DLL name 'FreeAddrInfoA';
+{$ENDIF}
+
+
+function WSAMakeSyncReply;
+begin
+ WSAMakeSyncReply := MakeLong(buflen, Error);
+end;
+
+function WSAMakeSelectReply;
+begin
+ WSAMakeSelectReply := MakeLong(Event, Error);
+end;
+
+function WSAGetAsyncBuflen(aParam: Longint): Word;
+begin
+ WSAGetAsyncBuflen := Word(aParam);
+end;
+
+function WSAGetAsyncError(aParam: Longint): Word;
+begin
+ WSAGetAsyncError := HIWORD(aParam);
+end;
+
+function WSAGetSelectEvent(aParam: Longint): Word;
+begin
+ Result := Word(aParam);
+end;
+
+function WSAGetSelectError(aParam: Longint): Word;
+begin
+ WSAGetSelectError := HIWORD(aParam);
+end;
+
+procedure FD_CLR(socket: TSocket; var FDSet: TFDSet);
+var
+ i: DWORD;
+begin
+ i := 0;
+ while i < FDSet.fd_count do
+ begin
+ if FDSet.fd_array[i] = socket then
+ begin
+ while i < FDSet.fd_count - 1 do
+ begin
+ FDSet.fd_array[i] := FDSet.fd_array[i + 1];
+ Inc(i);
+ end;
+ Dec(FDSet.fd_count);
+ Break;
+ end;
+ Inc(i);
+ end;
+end;
+
+function FD_ISSET(socket: TSocket; var FDSet: TFDSet): Boolean;
+begin
+ Result := __WSAFDIsSet(socket, FDSet);
+end;
+
+procedure FD_SET(socket: TSocket; var FDSet: TFDSet);
+begin
+ if FDSet.fd_count < FD_SETSIZE then
+ begin
+ FDSet.fd_array[FDSet.fd_count] := socket;
+ Inc(FDSet.fd_count);
+ end;
+end;
+
+procedure FD_ZERO(var FDSet: TFDSet);
+begin
+ FDSet.fd_count := 0;
+end;
+
+{ Initializes Winsock to version 2.2 }
+function InitWinsock: Boolean;
+var
+ ret: integer;
+ wsd: TWSAData;
+begin
+ ZeroMemory(@wsd, SizeOf(wsd));
+ ret := WSAStartup($0202, wsd);
+ if (ret = 0) then
+ Result := True
+ else
+ Result := False;
+end;
+
+{ Finalizes Winsock. }
+procedure FinWinsock;
+begin
+ WSACleanup;
+end;
+
+{ Returns text description of a winsock error. }
+function GetWinsockErrorText(const aError: integer): string;
+var
+ buffer: array [0 .. 255] of Char;
+ flags : DWORD;
+begin
+ FillChar(buffer, 256, #0);
+ flags := FORMAT_MESSAGE_FROM_SYSTEM or FORMAT_MESSAGE_IGNORE_INSERTS or FORMAT_MESSAGE_ARGUMENT_ARRAY;
+ FormatMessage(flags, nil, aError, 0, buffer, SizeOf(buffer), nil);
+ Result := buffer;
+end;
+
+{ Returns last winsock error description. }
+function GetLastWinsockErrorText: string;
+begin
+ Result := GetWinsockErrorText(WSAGetLastError);
+end;
+
+{ Creates a TCP socket. }
+function CreateTcpSock(const aAf: TAddressFamily): TSocket;
+begin
+ Result := socket(integer(aAf), SOCK_STREAM, IPPROTO_TCP);
+end;
+
+{ Creates a UDP socket. }
+function CreateUdpSock(const aAf: TAddressFamily): TSocket;
+begin
+ Result := socket(integer(aAf), SOCK_DGRAM, IPPROTO_UDP);
+end;
+
+{ Creates a RAW socket. }
+function CreateRawSock(const aAf: TAddressFamily = afIPv4): TSocket;
+begin
+ Result := socket(integer(aAf), SOCK_RAW, IPPROTO_RAW);
+end;
+
+{ Tries to connect a TCP socket to an address in aAddrPool. True on success, False if not. }
+function ConnectTCPSock(const aSock: TSocket; const aAddrPool: PAddrInfo): Boolean;
+var
+ curr: PAddrInfo;
+begin
+ Result := True;
+
+ curr := aAddrPool;
+ while (curr <> nil) do
+ begin
+ if (connect(aSock, curr^.ai_addr, curr^.ai_addrlen) <> 0) then
+ curr := curr^.ai_next
+ else
+ Break;
+
+ if (curr = nil) then
+ Exit(False);
+ end;
+end;
+
+{ Same as ConnectTCPSock but it treats WSAEWOULDBLOCK error as success. Use it for non-blocking sockets. }
+function ConnectTCPSockNonBlocking(const aSock: TSocket; const aAddrPool: PAddrInfo): Boolean;
+var
+ curr: PAddrInfo;
+begin
+ Result := True;
+
+ curr := aAddrPool;
+ while (curr <> nil) do
+ begin
+ if (connect(aSock, curr^.ai_addr, curr^.ai_addrlen) <> 0) then
+ begin
+ if (WSAGetLastError = WSAEWOULDBLOCK) then
+ Break;
+ curr := curr^.ai_next;
+ end
+ else
+ Break;
+
+ if (curr = nil) then
+ Exit(False);
+ end;
+end;
+
+{ Returns a socket connected to aHost:aPort, SOCKET_ERROR if something failed. Call WSAGetLastError if so. }
+function MakeTcpConnection(const aHost, aPort: string; const aAf: TAddressFamily): TSocket;
+label Error;
+var
+ addr: PAddrInfo;
+begin
+ Result := CreateTcpSock(aAf);
+ if (Result = INVALID_SOCKET) then
+ Exit;
+
+ if (GetAddrPool(aHost, aPort, addr, aAf) <> 0) then
+ goto Error;
+
+ if (ConnectTCPSock(Result, addr) = False) then
+ goto Error;
+
+ Exit;
+
+Error:
+ FreeAddrPool(addr);
+ closesocket(Result);
+end;
+
+{ Same as MakeTcpConnection but over Socks5 proxy. }
+function MakeTcpConnectionSocks5(const aHost, aPort, aProxyHost, aProxyPort, aProxyUser, aProxyPass: string; const aAf: TAddressFamily): TSocket;
+begin
+ Result := MakeTcpConnection(aProxyHost, aProxyPort, aAf);
+ if (Result = INVALID_SOCKET) then
+ Exit;
+
+ if (NegotiateSocks5(Result, aHost, aPort, aProxyUser, aProxyPass) = SOCKET_ERROR) then
+ begin
+ DeleteSock(Result);
+ Result := INVALID_SOCKET;
+ end;
+end;
+
+{ Sends a string over a TCP socket. }
+function SendStrTcp(const aSock: TSocket; const aString: string): integer;
+var
+ buffer: rawbytestring;
+begin
+ buffer := UTF8Encode(aString);
+ Result := send(aSock, buffer[1], Length(buffer), 0);
+end;
+
+{ Receives a string over a TCP socket. Result -2 on rtl error, -1 on winsock, 0 on close, >0 = bytes received. }
+function RecvStrTcp(const aSock: TSocket; var aString: string): integer;
+var
+ buf : pointer;
+ bufsize: u_long;
+ optlen : integer;
+begin
+ aString := '';
+
+ if (ioctlsocket(aSock, FIONREAD, bufsize) <> 0) then
+ Exit(SOCKET_ERROR);
+
+ if (bufsize = 0) then
+ begin
+ optlen := SizeOf(bufsize);
+ if (getsockopt(aSock, SOL_SOCKET, SO_RCVBUF, @integer(bufsize), optlen) <> 0) then
+ Exit(SOCKET_ERROR);
+ end;
+
+ buf := AllocMem(bufsize);
+ if (buf = nil) then
+ Exit( - 2);
+
+ Result := recv(aSock, buf^, bufsize, 0);
+ if (Result > 0) then
+ aString := string(PAnsiChar(buf));
+
+ FreeMemory(buf);
+end;
+
+{ Same as RecvStrTcp, but will immediately return empty aString and 0 if no data available. }
+function RecvStrTcpNonBlocking(const aSock: TSocket; var aString: string): integer;
+var
+ buf : pointer;
+ bufsize: u_long;
+begin
+ aString := '';
+
+ if (ioctlsocket(aSock, FIONREAD, bufsize) <> 0) then
+ Exit(SOCKET_ERROR);
+
+ if (bufsize = 0) then
+ Exit(SOCKET_ERROR);
+
+ buf := AllocMem(bufsize);
+ if (buf = nil) then
+ Exit( - 2);
+
+ Result := recv(aSock, buf^, bufsize, 0);
+ if (Result > 0) then
+ aString := string(PAnsiChar(buf));
+
+ FreeMemory(buf);
+end;
+
+{ closes and deletes a socket if its value is not INVALID_SOCKET. }
+procedure DeleteSock(var aSock: TSocket);
+begin
+ if (aSock = INVALID_SOCKET) then
+ Exit;
+ closesocket(aSock);
+ aSock := INVALID_SOCKET;
+end;
+
+{ Resolves aHost:aPort to an address pool in aAddrInfo. Returns 0 on success, Winsock Error otherwise. }
+function GetAddrPool(
+ const aHost, aPort: string; var aAddrInfo: PAddrInfo; const aAf: TAddressFamily;
+ const aSockType: TSocketType; const aProtocol: TIPProtocol; const aFlags: integer
+ ): integer;
+var
+ hints: TAddrInfo;
+begin
+ ZeroMemory(@hints, SizeOf(hints));
+ hints.ai_family := integer(aAf);
+ hints.ai_socktype := integer(aSockType);
+ hints.ai_protocol := integer(aProtocol);
+ hints.ai_flags := aFlags;
+
+ Result := GetAddrInfo(PChar(aHost), PChar(aPort), @hints, @aAddrInfo);
+end;
+
+{ Frees PAddrInfo. }
+procedure FreeAddrPool(var aAddrInfo: PAddrInfo);
+begin
+ if (aAddrInfo = nil) then
+ Exit;
+ FreeAddrInfo(aAddrInfo);
+ aAddrInfo := nil;
+end;
+
+{ Returns a text description of a Socks4 handshake error. }
+function GetSocks4ErrorText(const aErr: integer): string;
+begin
+ case aErr of
+ $5A:
+ Result := 'Request granted.';
+ $5B:
+ Result := 'Request rejected or failed.';
+ $5C:
+ Result := 'Request failed because client is not running identd (or unreachable).';
+ $5D:
+ Result := 'Request failed because client ident could not confirm user ID in request.';
+ else
+ Result := 'Unknown error.';
+ end;
+end;
+
+{ Returns a text description of a Socks5 handshake error. }
+function GetSocks5ErrorText(const aErr: integer): string;
+begin
+ case aErr of
+ 0:
+ Result := 'Connected OK.';
+ 1:
+ Result := 'General failure.';
+ 2:
+ Result := 'Connection not allowed by ruleset.';
+ 3:
+ Result := 'Network unreachable.';
+ 4:
+ Result := 'Host unreachable.';
+ 5:
+ Result := 'Connection refused by destination host.';
+ 6:
+ Result := 'TTL expired.';
+ 7:
+ Result := 'Command not supported / protocol error.';
+ 8:
+ Result := 'Address type not supported.';
+ else
+ Result := 'Unknown error.';
+ end;
+end;
+
+{ Negotiates a client connection with a HTTP proxy ON A BLOCKING SOCKET! }
+{ aUser is optional, if HTTP proxy requests is for auth. }
+{ Returns 0 on success, SOCKET_ERROR on winsock error, or a >0 value for Proxy error. }
+{ Supports NoAuth and User Auth. }
+function NegotiateProxy(const aSocket: TSocket; const aHost, aPort, aUser: string): integer;
+begin
+ Result := 0;
+end;
+
+{ Negotiates a client connection with a socks4 proxy ON A BLOCKING SOCKET! }
+{ aUser, apass are optional, if Socks4 server requests them for an User/Pass auth. }
+{ Returns 0 on success, SOCKET_ERROR on winsock error, or a >0 value for Socks4 error. }
+{ Supports NoAuth and User/Pass. }
+function NegotiateSocks4(const aSocket: TSocket; const aHost, aPort, aUser, aPass: string): integer;
+begin
+ Result := 0;
+end;
+
+{ Negotiates a client connection with a socks5 proxy ON A BLOCKING SOCKET! }
+{ aUser, aPass are optional, if Socks5 server requests them for an User/Pass auth. }
+{ Returns 0 on success, SOCKET_ERROR on winsock error, or a >0 value for Socks5 error. }
+{ Supports NoAuth and User/Pass. }
+function NegotiateSocks5(const aSocket: TSocket; const aHost, aPort, aUser, aPass: string): integer;
+
+ function IsError(const aErr: integer): Boolean;
+ begin
+ if (aErr <= 0) or (aErr = SOCKET_ERROR) then
+ Result := True
+ else
+ Result := False;
+ end;
+
+var
+ Buff : array of Byte;
+ host : ansistring;
+ port : Word;
+ uname: ansistring;
+ pword: ansistring;
+begin
+ // Send auth methods.
+ SetLength(Buff, 4);
+ Buff[0] := $05; // Socks version, must be $05.
+ Buff[1] := $02; // Num of methods supported.
+ Buff[2] := $00; // Method 1 - No auth.
+ Buff[3] := $02; // Method 2 - Username/Password.
+ Result := send(aSocket, Buff[0], Length(Buff), 0);
+ if IsError(Result) then
+ Exit(SOCKET_ERROR);
+
+ // Recieve selected Auth method.
+ SetLength(Buff, 2);
+ ZeroMemory(@Buff[0], 2);
+ Result := recv(aSocket, Buff[0], Length(Buff), MSG_WAITALL);
+ if IsError(Result) then
+ Exit(SOCKET_ERROR);
+
+ // Check reply version.
+ if (Buff[0] <> $05) then // Socks version, must be $05.
+ Exit(1);
+
+ // Do User/Pass auth.
+ if (Buff[1] = 2) then
+ begin
+ // Send Username/Password
+ uname := ansistring(aUser);
+ pword := ansistring(aPass);
+
+ SetLength(Buff, 3 + Length(uname) + Length(pword));
+ Buff[0] := $01; // Sending user:pass auth.
+
+ // Put username
+ Buff[1] := Length(uname);
+ if (Buff[1] > 0) then
+ CopyMemory(@Buff[2], @uname[1], Length(uname));
+
+ // Put password
+ Buff[2 + Length(uname) + 1] := Length(pword);
+ if (Buff[2 + Length(uname) + 1] > 0) then
+ CopyMemory(@Buff[2 + Length(uname) + 1], @pword[1], Length(pword));
+
+ // Send Username:Password auth.
+ Result := send(aSocket, Buff[0], Length(Buff), 0);
+ if (IsError(Result)) then
+ Exit(SOCKET_ERROR);
+
+ // Get auth response.
+ SetLength(Buff, 2);
+ ZeroMemory(@Buff[0], 2);
+ Result := recv(aSocket, Buff[0], Length(Buff), MSG_WAITALL);
+ if IsError(Result) then
+ Exit(SOCKET_ERROR);
+ end
+ else if (Buff[1] <> 0) then // Some unsupported auth method requested.
+ Exit(1);
+
+ // Send connect request.
+ host := ansistring(aHost);
+ ServToPortNum(aPort, port);
+ SetLength(Buff, 7 + Length(host));
+ Buff[0] := $05; // Socks version.
+ Buff[1] := $01; // Establish TCP connection.
+ Buff[2] := $00; // Reserved.
+ Buff[3] := $03; // Destination type: Domain name.
+ Buff[4] := Length(host); // Length of hostname
+ CopyMemory(@Buff[5], PAnsiChar(host), Buff[4]); // Hostname
+ CopyMemory(@Buff[5 + Buff[4]], @port, SizeOf(port)); // Port
+
+ Result := send(aSocket, Buff[0], Length(Buff), 0);
+ if IsError(Result) then
+ Exit(SOCKET_ERROR);
+
+ // Recieve connect response.
+ SetLength(Buff, 260);
+ FillChar(Buff[0], 260, 0);
+ Result := recv(aSocket, Buff[0], 260, 0);
+ if IsError(Result) then
+ Exit(SOCKET_ERROR);
+
+ // Check for final "OK!".
+ if (Buff[1] <> $00) then
+ Exit(1);
+end;
+
+{ Returns an IP string from PSockAddr in standard dotted format: byte.byte.byte.byte:word (ip:port). }
+{ Supports IPv6 addresses as well, uses Winsock functions to convert data. }
+function SockAddrToStr(const aSockAddr: PSockAddr; const aAddrLen: integer; var aOutString: string): Boolean;
+var
+ buffer : array [0 .. 255] of Char;
+ buffersize: cardinal;
+begin
+ if (aSockAddr = nil) or (aAddrLen = 0) then
+ Exit(False);
+
+ buffersize := 256;
+ ZeroMemory(@buffer[0], buffersize);
+ if (WSAAddressToString(aSockAddr, aAddrLen, nil, buffer, buffersize) = 0) then
+ begin
+ SetString(aOutString, PChar(@buffer[0]), buffersize);
+ Result := True;
+ end
+ else
+ begin
+ aOutString := '';
+ Result := False;
+ end;
+end;
+
+{ Returns an IP string from PSockAddr in standard dotted format: byte.byte.byte.byte:word (ip:port). }
+function SockAddrToStr(const aSockAddr: PSockAddr; const aAddrLen: integer): string; overload;
+var
+ s: string;
+begin
+ Result := '';
+ if (SockAddrToStr(aSockAddr, aAddrLen, s)) then
+ Result := s;
+end;
+
+{ Returns port number for a service name in net byte order. i.e. "http -> 80" }
+function ServToPortNum(const aServName: string; var aPort: Word): Boolean;
+var
+ sent: PServEnt;
+ code: integer;
+begin
+ Result := False;
+
+ sent := getservbyname(PAnsiChar(ansistring(aServName)), PAnsiChar('tcp'));
+ if (sent = nil) then
+ begin
+ Val(aServName, aPort, code);
+ if (code <> 0) then
+ Exit;
+ aPort := htons(aPort);
+ end
+ else
+ aPort := sent^.s_port;
+
+ Result := True;
+end;
+
+{ Converts in_addr to text representation. ~10x faster than inet_ntoa. }
+function InAddr4ToStr(const aAddr: in_addr): string;
+type
+ TIP4Bytes = array [0 .. 3] of byte;
+var
+ s: shortstring;
+begin
+ Str(TIP4Bytes(aAddr)[0], s);
+ Result := string(s);
+ Str(TIP4Bytes(aAddr)[1], s);
+ Result := Result + '.' + string(s);
+ Str(TIP4Bytes(aAddr)[2], s);
+ Result := Result + '.' + string(s);
+ Str(TIP4Bytes(aAddr)[3], s);
+ Result := Result + '.' + string(s);
+end;
+
+{ Converts in6_addr to text representation. If aAbbreviate collapses leading and consecutive zeros. }
+function InAddr6ToStr(const aAddr: in6_addr; const aAbbreviate: boolean = True): string;
+var
+ i: integer;
+begin
+ Result := '';
+
+ if (aAbbreviate) then
+ begin
+ for i := 0 to 7 do
+ begin
+ if (aAddr.Words[i] <> 0) then
+ begin
+ if (aAddr.Bytes[i * 2] <> 0) then
+ begin
+ Result := Result + TextIntToHex(aAddr.Bytes[i * 2], 1);
+ Result := Result + TextIntToHex(aAddr.Bytes[i * 2 + 1], 2);
+ end
+ else
+ Result := Result + TextIntToHex(aAddr.Bytes[i * 2 + 1], 1);
+ end;
+
+ if not (TextEnds(Result, '::')) then
+ if (i <> 7) then
+ Result := Result + ':';
+ end;
+ Exit;
+ end;
+
+ for i := 0 to 15 do
+ begin
+ Result := Result + TextIntToHex(aAddr.Bytes[i], 2);
+ if (i <> 15) and (Odd(i)) then
+ Result := Result + ':';
+ end;
+end;
+
+{ Performs a reverse lookup on a ipv4 address. On failure result will be empty. }
+function InAddr4RevLookup(const aAddr: in_addr; const aDGram: boolean = False): string;
+var
+ addr : sockaddr_in;
+ hostName: array [0 .. NI_MAXHOST - 1] of ansichar;
+ servName: array [0 .. NI_MAXSERV - 1] of ansichar;
+ flags : integer;
+begin
+ Result := CEmpty;
+
+ if (aDGram) then
+ flags := NI_NAMEREQD or NI_DGRAM or NI_NUMERICHOST
+ else
+ flags := NI_NAMEREQD or NI_NUMERICHOST;
+
+ ZeroMemory(@addr, SizeOf(addr));
+ ZeroMemory(@hostName[0], Length(hostName));
+ ZeroMemory(@servName[0], Length(servName));
+
+ addr.sin_family := AF_INET;
+ addr.sin_addr.S_addr := aAddr.S_addr;
+ addr.sin_port := 0;
+
+ if (getnameinfo(@addr, SizeOf(addr), hostName, Length(hostName), servName, Length(servName), flags) = 0) then
+ Result := string(hostName);
+end;
+
+{ Performs a reverse lookup on a ipv6 address. On failure result will be empty. }
+function InAddr6RevLookup(const aAddr: in6_addr; const aDGram: boolean = False): string;
+var
+ addr : sockaddr_in6;
+ hostName: array [0 .. NI_MAXHOST - 1] of ansichar;
+ servName: array [0 .. NI_MAXSERV - 1] of ansichar;
+ flags : integer;
+begin
+ Result := CEmpty;
+
+ if (aDGram) then
+ flags := NI_NAMEREQD or NI_DGRAM or NI_NUMERICHOST
+ else
+ flags := NI_NAMEREQD or NI_NUMERICHOST;
+
+ ZeroMemory(@addr, SizeOf(addr));
+ ZeroMemory(@hostName[0], Length(hostName));
+ ZeroMemory(@servName[0], Length(servName));
+
+ addr.sin6_family := AF_INET6;
+ addr.sin6_addr := aAddr;
+ addr.sin6_port := 0;
+
+ if (getnameinfo(@addr, SizeOf(addr), hostName, Length(hostName), servName, Length(servName), flags) = 0) then
+ Result := string(hostName);
+end;
+
+{ TProxyType to string. }
+function ProxyTypeToString(const aProxyType: TProxyType): string;
+begin
+ case aProxyType of
+ ptNone:
+ Result := '';
+ ptHTTP:
+ Result := 'HTTP';
+ ptSocks4:
+ Result := 'Socks4';
+ ptSocks5:
+ Result := 'Socks5';
+ end;
+end;
+
+{ TProxyType to URI scheme. }
+function ProxyTypeToScheme(const aProxyType: TProxyType): string;
+begin
+ case aProxyType of
+ ptNone:
+ Result := '';
+ ptHTTP:
+ Result := 'http://';
+ ptSocks4:
+ Result := 'socks4://';
+ ptSocks5:
+ Result := 'socks5://';
+ end;
+end;
+
+{ ===================== }
+{ TGetAddrPoolAsyncData }
+{ ===================== }
+
+{ GetAddrPoolAsync thread procedure. }
+class function TGetAddrPoolAsyncData.GetAddrPoolAsyncThread(aParam: pointer): DWORD;
+var
+ data: PGetAddrPoolAsyncData;
+ addr: PAddrInfo;
+ ret : integer;
+begin
+ Result := 0;
+
+ data := PGetAddrPoolAsyncData(aParam);
+ ret := GetAddrPool(data^.host, data^.port, addr, data^.AddressFamily, data^.SocketType);
+ data^.ThreadHandle := 0;
+ if (Assigned(data^.OnResolved)) then
+ data^.OnResolved(addr, ret);
+end;
+
+{ Constructor. Use this as constructor. }
+procedure TGetAddrPoolAsyncData.Initialize;
+begin
+ host := '';
+ port := '';
+ AddressFamily := afUnspec;
+ SocketType := stStream;
+ OnResolved := nil;
+ ThreadHandle := 0;
+end;
+
+{ Aborts the thread if its running. }
+procedure TGetAddrPoolAsyncData.Abort;
+begin
+ if (ThreadHandle <> 0) then
+ begin
+ TerminateThread(ThreadHandle, 0);
+ ThreadHandle := 0;
+ end;
+ Initialize;
+end;
+
+{ Tells if the resolve thread for this data is still running. }
+function TGetAddrPoolAsyncData.Running: boolean;
+begin
+ Result := (ThreadHandle <> 0);
+end;
+
+{ Calls GetAddrInfo in a thread. }
+procedure GetAddrPoolAsync(var aData: TGetAddrPoolAsyncData);
+var
+ ThreadHandle: THandle;
+ threadID : cardinal;
+begin
+ threadID := 0;
+ ThreadHandle := CreateThread(nil, 0, @aData.GetAddrPoolAsyncThread, @aData, CREATE_SUSPENDED, threadID);
+ if (ThreadHandle <> 0) then
+ begin
+ aData.ThreadHandle := ThreadHandle;
+ ResumeThread(ThreadHandle);
+ end;
+end;
+
+end.
diff --git a/EvilWorks.Api.IpHlpApi.pas b/EvilWorks.Api.IpHlpApi.pas
new file mode 100644
index 0000000..64fac58
--- /dev/null
+++ b/EvilWorks.Api.IpHlpApi.pas
@@ -0,0 +1,500 @@
+unit EvilWorks.Api.IpHlpApi;
+
+interface
+
+uses
+ WinApi.Windows,
+ WinApi.Winsock2,
+ WinApi.IpHlpApi,
+ WinApi.IpRtrMib,
+ WinApi.IpExport,
+ System.SysUtils,
+ EvilWorks.Api.TcpEStats;
+
+const
+ { TCPIP_OWNING_MODULE_SIZE }
+ TCPIP_OWNING_MODULE_SIZE = 16;
+{$EXTERNALSYM TCPIP_OWNING_MODULE_SIZE}
+
+
+type
+
+ TMacAddr = array [0 .. MAXLEN_PHYSADDR - 1] of byte;
+ PMacAddr = ^TMacAddr;
+
+ { MIB_TCP_STATE }
+ MIB_TCP_STATE = (
+ MIB_TCP_STATE_CLOSED = 1,
+ MIB_TCP_STATE_LISTEN = 2,
+ MIB_TCP_STATE_SYN_SENT = 3,
+ MIB_TCP_STATE_SYN_RCVD = 4,
+ MIB_TCP_STATE_ESTAB = 5,
+ MIB_TCP_STATE_FIN_WAIT1 = 6,
+ MIB_TCP_STATE_FIN_WAIT2 = 7,
+ MIB_TCP_STATE_CLOSE_WAIT = 8,
+ MIB_TCP_STATE_CLOSING = 9,
+ MIB_TCP_STATE_LAST_ACK = 10,
+ MIB_TCP_STATE_TIME_WAIT = 11,
+ MIB_TCP_STATE_DELETE_TCB = 12
+ );
+{$EXTERNALSYM MIB_TCP_STATE}
+ { TCP_TABLE_CLASS }
+ TCP_TABLE_CLASS = (
+ TCP_TABLE_BASIC_LISTENER,
+ TCP_TABLE_BASIC_CONNECTIONS,
+ TCP_TABLE_BASIC_ALL,
+ TCP_TABLE_OWNER_PID_LISTENER,
+ TCP_TABLE_OWNER_PID_CONNECTIONS,
+ TCP_TABLE_OWNER_PID_ALL,
+ TCP_TABLE_OWNER_MODULE_LISTENER,
+ TCP_TABLE_OWNER_MODULE_CONNECTIONS,
+ TCP_TABLE_OWNER_MODULE_ALL
+ );
+{$EXTERNALSYM TCP_TABLE_CLASS}
+ TTcpTableClass = TCP_TABLE_CLASS;
+ PTCP_TABLE_CLASS = ^TCP_TABLE_CLASS;
+
+ { UDP_TABLE_CLASS }
+ UDP_TABLE_CLASS = (
+ UDP_TABLE_BASIC,
+ UDP_TABLE_OWNER_PID,
+ UDP_TABLE_OWNER_MODULE
+ );
+{$EXTERNALSYM UDP_TABLE_CLASS}
+ TUdpTableClass = UDP_TABLE_CLASS;
+ PDUDP_TABLE_CLASS = ^UDP_TABLE_CLASS;
+
+ { MIB_TCPROW }
+ MIB_TCPROW = record
+ State: MIB_TCP_STATE;
+ dwLocalAddr: DWORD;
+ dwLocalPort: DWORD;
+ dwRemoteAddr: DWORD;
+ dwRemotePort: DWORD;
+ end;
+{$EXTERNALSYM PMIB_TCPROW}
+
+ PMIB_TCPROW = ^MIB_TCPROW;
+{$EXTERNALSYM MIB_TCPROW}
+ TMibTcpRow = MIB_TCPROW;
+
+ { MIB_TCPTABLE }
+ MIB_TCPTABLE = record
+ dwNumEntries: DWORD;
+ table: array [0 .. 0] of MIB_TCPROW;
+ end;
+{$EXTERNALSYM MIB_TCPTABLE}
+
+ PMIB_TCPTABLE = ^MIB_TCPTABLE;
+{$EXTERNALSYM MIB_TCPTABLE}
+ TMibTcpTable = MIB_TCPTABLE;
+
+ { MIB_TCPROW_OWNER_PID }
+ MIB_TCPROW_OWNER_PID = record
+ dwState: DWORD;
+ dwLocalAddr: DWORD;
+ dwLocalPort: DWORD;
+ dwRemoteAddr: DWORD;
+ dwRemotePort: DWORD;
+ dwOwningPid: DWORD;
+ end;
+{$EXTERNALSYM MIB_TCPROW_OWNER_PID}
+
+ PMIB_TCPROW_OWNER_PID = ^MIB_TCPROW_OWNER_PID;
+{$EXTERNALSYM MIB_TCPROW_OWNER_PID}
+ TMibTcpRowOwnerPid = MIB_TCPROW_OWNER_PID;
+
+ { MIB_TCPTABLE_OWNER_PID }
+ MIB_TCPTABLE_OWNER_PID = record
+ dwNumEntries: DWORD;
+ table: array [0 .. 0] of MIB_TCPROW_OWNER_PID;
+ end;
+{$EXTERNALSYM MIB_TCPTABLE_OWNER_PID}
+
+ PMIB_TCPTABLE_OWNER_PID = ^MIB_TCPTABLE_OWNER_PID;
+{$EXTERNALSYM MIB_TCPTABLE_OWNER_PID}
+ TMibTcpTableOwnerPid = MIB_TCPTABLE_OWNER_PID;
+
+ { MIB_TCPROW_OWNER_MODULE }
+ MIB_TCPROW_OWNER_MODULE = record
+ dwState: DWORD;
+ dwLocalAddr: DWORD;
+ dwLocalPort: DWORD;
+ dwRemoteAddr: DWORD;
+ dwRemotePort: DWORD;
+ dwOwningPid: DWORD;
+ liCreateTimestamp: LARGE_INTEGER;
+ OwningModuleInfo: array [0 .. TCPIP_OWNING_MODULE_SIZE - 1] of ULONGLONG;
+ end;
+{$EXTERNALSYM MIB_TCPROW_OWNER_MODULE}
+
+ PMIB_TCPROW_OWNER_MODULE = ^MIB_TCPROW_OWNER_MODULE;
+{$EXTERNALSYM MIB_TCPROW_OWNER_MODULE}
+ TMibTcpRowOwnerModule = MIB_TCPROW_OWNER_MODULE;
+
+ { MIB_TCPTABLE_OWNER_MODULE }
+ MIB_TCPTABLE_OWNER_MODULE = record
+ dwNumEntries: DWORD;
+ table: array [0 .. 0] of MIB_TCPROW_OWNER_MODULE;
+ end;
+{$EXTERNALSYM MIB_TCPTABLE_OWNER_MODULE}
+
+ PMIB_TCPTABLE_OWNER_MODULE = ^MIB_TCPTABLE_OWNER_MODULE;
+{$EXTERNALSYM MIB_TCPTABLE_OWNER_MODULE}
+ TMibTcpTableOwnerModule = MIB_TCPTABLE_OWNER_MODULE;
+
+ { MIB_TCP6ROW }
+ MIB_TCP6ROW = record
+ State: MIB_TCP_STATE;
+ LocalAddr: IN6_ADDR;
+ dwLocalScopeId: DWORD;
+ dwLocalPort: DWORD;
+ RemoteAddr: IN6_ADDR;
+ dwRemoteScopeId: DWORD;
+ dwRemotePort: DWORD;
+ end;
+{$EXTERNALSYM MIB_TCP6ROW}
+
+ PMIB_TCP6ROW = ^MIB_TCP6ROW;
+{$EXTERNALSYM MIB_TCP6ROW}
+ TMibTcp6Row = MIB_TCP6ROW;
+
+ { MIB_TCP6TABLE }
+ MIB_TCP6TABLE = record
+ dwNumEntries: DWORD;
+ table: array [0 .. 0] of MIB_TCP6ROW;
+ end;
+{$EXTERNALSYM MIB_TCP6TABLE}
+
+ PMIB_TCP6TABLE = ^MIB_TCP6TABLE;
+{$EXTERNALSYM MIB_TCP6TABLE}
+ TMibTcp6Table = MIB_TCP6TABLE;
+
+ { MIB_TCP6ROW_OWNER_PID }
+ MIB_TCP6ROW_OWNER_PID = record
+ ucLocalAddr: array [0 .. 15] of UCHAR;
+ dwLocalScopeId: DWORD;
+ dwLocalPort: DWORD;
+ ucRemoteAddr: array [0 .. 15] of UCHAR;
+ dwRemoteScopeId: DWORD;
+ dwRemotePort: DWORD;
+ dwState: DWORD;
+ dwOwningPid: DWORD;
+ end;
+{$EXTERNALSYM MIB_TCP6ROW_OWNER_PID}
+
+ PMIB_TCP6ROW_OWNER_PID = ^MIB_TCP6ROW_OWNER_PID;
+{$EXTERNALSYM MIB_TCP6ROW_OWNER_PID}
+ TMibTcp6RowOwnerPid = MIB_TCP6ROW_OWNER_PID;
+
+ { MIB_TCP6TABLE_OWNER_PID }
+ MIB_TCP6TABLE_OWNER_PID = record
+ dwNumEntries: DWORD;
+ table: array [0 .. 0] of MIB_TCP6ROW_OWNER_PID;
+ end;
+{$EXTERNALSYM MIB_TCP6TABLE_OWNER_PID}
+
+ PMIB_TCP6TABLE_OWNER_PID = ^MIB_TCP6TABLE_OWNER_PID;
+{$EXTERNALSYM MIB_TCP6ROW_OWNER_PID}
+ TMibTcp6TableOwnerPid = MIB_TCP6TABLE_OWNER_PID;
+
+ { MIB_TCP6ROW_OWNER_MODULE }
+ MIB_TCP6ROW_OWNER_MODULE = record
+ ucLocalAddr: array [0 .. 15] of UCHAR;
+ dwLocalScopeId: DWORD;
+ dwLocalPort: DWORD;
+ ucRemoteAddr: array [0 .. 15] of UCHAR;
+ dwRemoteScopeId: DWORD;
+ dwRemotePort: DWORD;
+ dwState: DWORD;
+ dwOwningPid: DWORD;
+ liCreateTimestamp: LARGE_INTEGER;
+ OwningModuleInfo: array [0 .. TCPIP_OWNING_MODULE_SIZE - 1] of ULONGLONG;
+ end;
+{$EXTERNALSYM MIB_TCP6ROW_OWNER_MODULE}
+
+ PMIB_TCP6ROW_OWNER_MODULE = ^MIB_TCP6ROW_OWNER_MODULE;
+{$EXTERNALSYM MIB_TCP6ROW_OWNER_MODULE}
+ TMibTcp6RowOwnerModule = MIB_TCP6ROW_OWNER_MODULE;
+
+ { MIB_TCP6TABLE_OWNER_MODULE }
+ MIB_TCP6TABLE_OWNER_MODULE = record
+ dwNumEntries: DWORD;
+ table: array [0 .. 0] of MIB_TCP6ROW_OWNER_MODULE;
+ end;
+{$EXTERNALSYM MIB_TCP6TABLE_OWNER_MODULE}
+
+ PMIB_TCP6TABLE_OWNER_MODULE = ^MIB_TCP6TABLE_OWNER_MODULE;
+{$EXTERNALSYM MIB_TCP6TABLE_OWNER_MODULE}
+ TMibTcp6TableOwnerModule = MIB_TCP6TABLE_OWNER_MODULE;
+
+ { MIB_UDPROW }
+ MIB_UDPROW = record
+ dwLocalAddr: DWORD;
+ dwLocalPort: DWORD;
+ end;
+{$EXTERNALSYM MIB_UDPROW}
+
+ TMibUdpRow = MIB_UDPROW;
+ PMIB_UDPROW = ^MIB_UDPROW;
+
+ { MIB_UDPTABLE }
+ MIB_UDPTABLE = record
+ dwNumEntries: DWORD;
+ table: array [0 .. 0] of MIB_UDPROW;
+ end;
+{$EXTERNALSYM MIB_UDPTABLE}
+
+ TMibUdpTable = MIB_UDPTABLE;
+ PMIB_UDPTABLE = ^MIB_UDPTABLE;
+
+ { MIB_UDPROW_OWNER_PID }
+ MIB_UDPROW_OWNER_PID = record
+ dwLocalAddr: DWORD;
+ dwLocalPort: DWORD;
+ dwOwningPid: DWORD;
+ end;
+{$EXTERNALSYM MIB_UDPROW_OWNER_PID}
+
+ TMibUdpRowOwnerPid = MIB_UDPROW_OWNER_PID;
+ PMIB_UDPROW_OWNER_PID = ^MIB_UDPROW_OWNER_PID;
+
+ { MIB_UDPTABLE_OWNER_PID }
+ MIB_UDPTABLE_OWNER_PID = record
+ dwNumEntries: DWORD;
+ table: array [0 .. 0] of MIB_UDPROW_OWNER_PID;
+ end;
+{$EXTERNALSYM MIB_UDPTABLE_OWNER_PID}
+
+ TMibUdpTableOwnerPid = MIB_UDPTABLE_OWNER_PID;
+ PMIB_UDPTABLE_OWNER_PID = ^MIB_UDPTABLE_OWNER_PID;
+
+ { MIB_UDPROW_OWNER_MODULE }
+ MIB_UDPROW_OWNER_MODULE = record
+ dwLocalAddr: DWORD;
+ dwLocalPort: DWORD;
+ dwOwningPid: DWORD;
+ liCreateTimestamp: LARGE_INTEGER;
+ dwFlags: integer;
+ OwningModuleInfo: array [0 .. TCPIP_OWNING_MODULE_SIZE - 1] of ULONGLONG;
+ end;
+{$EXTERNALSYM MIB_UDPROW_OWNER_MODULE}
+
+ TMibUdpRowOwnerModule = MIB_UDPROW_OWNER_MODULE;
+ PMIB_UDPROW_OWNER_MODULE = ^MIB_UDPROW_OWNER_MODULE;
+
+ { MIB_UDPTABLE_OWNER_MODULE }
+ MIB_UDPTABLE_OWNER_MODULE = record
+ dwNumEntries: DWORD;
+ table: array [0 .. 0] of MIB_UDPROW_OWNER_MODULE;
+ end;
+{$EXTERNALSYM MIB_UDPTABLE_OWNER_MODULE}
+
+ TMibUdpTableOwnerModule = MIB_UDPTABLE_OWNER_MODULE;
+ PMIB_UDPTABLE_OWNER_MODULE = ^MIB_UDPTABLE_OWNER_MODULE;
+
+ { MIB_UDP6ROW }
+ MIB_UDP6ROW = record
+ dwLocalAddr: IN6_ADDR;
+ dwLocalScopeId: DWORD;
+ dwLocalPort: DWORD;
+ end;
+{$EXTERNALSYM MIB_UDP6ROW}
+
+ TMibUdp6Row = MIB_UDP6ROW;
+ PMIB_UDP6ROW = ^MIB_UDP6ROW;
+
+ { MIB_UDP6TABLE }
+ MIB_UDP6TABLE = record
+ dwNumEntries: DWORD;
+ table: array [0 .. 0] of MIB_UDP6ROW;
+ end;
+{$EXTERNALSYM MIB_UDP6TABLE}
+
+ TMibUdp6Table = MIB_UDP6TABLE;
+ PMIB_UDP6TABLE = ^MIB_UDP6TABLE;
+
+ { MIB_UDPROW_OWNER_PID }
+ MIB_UDP6ROW_OWNER_PID = record
+ ucLocalAddr: array [0 .. 15] of UCHAR;
+ dwLocalScopeId: DWORD;
+ dwLocalPort: DWORD;
+ dwOwningPid: DWORD;
+ end;
+{$EXTERNALSYM MIB_UDP6ROW_OWNER_PID}
+
+ TMibUdp6RowOwnerPid = MIB_UDP6ROW_OWNER_PID;
+ PMIB_UDP6ROW_OWNER_PID = ^MIB_UDP6ROW_OWNER_PID;
+
+ { MIB_UDP6TABLE_OWNER_PID }
+ MIB_UDP6TABLE_OWNER_PID = record
+ dwNumEntries: DWORD;
+ table: array [0 .. 0] of MIB_UDP6ROW_OWNER_PID;
+ end;
+{$EXTERNALSYM MIB_UDP6TABLE_OWNER_PID}
+
+ TMibUdp6TableOwnerPid = MIB_UDP6TABLE_OWNER_PID;
+ PMIB_UDP6TABLE_OWNER_PID = ^MIB_UDP6TABLE_OWNER_PID;
+
+ { MIB_UDP6ROW_OWNER_MODULE }
+ MIB_UDP6ROW_OWNER_MODULE = record
+ ucLocalAddr: array [0 .. 15] of UCHAR;
+ dwLocalScopeId: DWORD;
+ dwLocalPort: DWORD;
+ dwOwningPid: DWORD;
+ liCreateTimestamp: LARGE_INTEGER;
+ dwFlags: integer;
+ OwningModuleInfo: array [0 .. TCPIP_OWNING_MODULE_SIZE - 1] of ULONGLONG;
+ end;
+{$EXTERNALSYM MIB_UDP6ROW_OWNER_MODULE}
+
+ TMibUdp6RowOwnerModule = MIB_UDP6ROW_OWNER_MODULE;
+ PMIB_UDP6ROW_OWNER_MODULE = ^MIB_UDP6ROW_OWNER_MODULE;
+
+ { MIB_UDP6TABLE_OWNER_MODULE }
+ MIB_UDP6TABLE_OWNER_MODULE = record
+ dwNumEntries: DWORD;
+ table: array [0 .. 0] of MIB_UDP6ROW_OWNER_MODULE;
+ end;
+{$EXTERNALSYM MIB_UDP6TABLE_OWNER_MODULE}
+
+ TMibUdp6TableOwnerModule = MIB_UDP6TABLE_OWNER_MODULE;
+ PMIB_UDP6TABLE_OWNER_MODULE = ^MIB_UDP6TABLE_OWNER_MODULE;
+
+ TGetPerTcpConnectionEStats = function(Row: PMIB_TCPROW; EstatsType: TCP_ESTATS_TYPE;
+ Rw: PUCHAR; RwVersion: ULONG; RwSize: ULONG; Ros: PUCHAR; RosVersion: ULONG;
+ RosSize: ULONG; Rod: PUCHAR; RodVersion: ULONG; RodSize: ULONG): ULONG; stdcall;
+ TSetPerTcpConnectionEStats = function(Row: PMIB_TCPROW; EstatsType: TCP_ESTATS_TYPE;
+ Rw: PUCHAR; RwVersion: ULONG; RwSize: ULONG; Offset: ULONG): ULONG; stdcall;
+ TGetPerTcp6ConnectionEStats = function(Row: PMIB_TCP6ROW; EstatsType: TCP_ESTATS_TYPE;
+ Rw: PUCHAR; RwVersion: ULONG; RwSize: ULONG; Ros: PUCHAR; RosVersion: ULONG;
+ RosSize: ULONG; Rod: PUCHAR; RodVersion: ULONG; RodSize: ULONG): ULONG; stdcall;
+ TSetPerTcp6ConnectionEStats = function(Row: PMIB_TCP6ROW; EstatsType: TCP_ESTATS_TYPE;
+ Rw: PUCHAR; RwVersion: ULONG; RwSize: ULONG; Offset: ULONG): ULONG; stdcall;
+
+function GetExtendedTcpTable(
+ pTcpTable: pointer; var dwSize: DWORD; bOrder: BOOL; ulAf: ULONG;
+ TableClass: TCP_TABLE_CLASS; Reserved: ULONG): DWORD; stdcall;
+{$EXTERNALSYM GetExtendedTcpTable}
+
+function GetExtendedUdpTable(
+ pUdpTable: pointer; var dwSize: DWORD; bOrder: BOOL; ulAf: ULONG;
+ TableClass: UDP_TABLE_CLASS; Reserved: ULONG): DWORD; stdcall;
+{$EXTERNALSYM GetExtendedUdpTable}
+
+function GetPerTcpConnectionEStats(Row: PMIB_TCPROW; EstatsType: TCP_ESTATS_TYPE;
+ Rw: PUCHAR; RwVersion: ULONG; RwSize: ULONG; Ros: PUCHAR; RosVersion: ULONG;
+ RosSize: ULONG; Rod: PUCHAR; RodVersion: ULONG; RodSize: ULONG): ULONG; stdcall;
+{$EXTERNALSYM GetPerTcpConnectionEStats}
+
+function SetPerTcpConnectionEStats(Row: PMIB_TCPROW; EstatsType: TCP_ESTATS_TYPE;
+ Rw: PUCHAR; RwVersion: ULONG; RwSize: ULONG; Offset: ULONG): ULONG; stdcall;
+{$EXTERNALSYM SetPerTcpConnectionEStats}
+
+function GetPerTcp6ConnectionEStats(Row: PMIB_TCP6ROW; EstatsType: TCP_ESTATS_TYPE;
+ Rw: PUCHAR; RwVersion: ULONG; RwSize: ULONG; Ros: PUCHAR; RosVersion: ULONG;
+ RosSize: ULONG; Rod: PUCHAR; RodVersion: ULONG; RodSize: ULONG): ULONG; stdcall;
+{$EXTERNALSYM GetPerTcp6ConnectionEStats}
+
+function SetPerTcp6ConnectionEStats(Row: PMIB_TCP6ROW; EstatsType: TCP_ESTATS_TYPE;
+ Rw: PUCHAR; RwVersion: ULONG; RwSize: ULONG; Offset: ULONG): ULONG; stdcall;
+{$EXTERNALSYM SetPerTcp6ConnectionEStats}
+
+function MacAddr2Str(const aMacAddr: TMacAddr; aSize: integer): string;
+
+implementation
+
+const
+ iphlpapilib = 'iphlpapi.dll';
+
+var
+ hIpHlpApi : THandle;
+ _GetPerTcpConnectionEStats : TGetPerTcpConnectionEStats;
+ _SetPerTcpConnectionEStats : TSetPerTcpConnectionEStats;
+ _GetPerTcp6ConnectionEStats: TGetPerTcp6ConnectionEStats;
+ _SetPerTcp6ConnectionEStats: TSetPerTcp6ConnectionEStats;
+
+function CheckStubsLoaded: boolean;
+begin
+ if (hIpHlpApi = 0) then
+ begin
+ hIpHlpApi := LoadLibrary(iphlpapilib);
+ if (hIpHlpApi < 32) then
+ begin
+ hIpHlpApi := 0;
+ Result := False;
+ Exit;
+ end;
+ @_GetPerTcpConnectionEStats := GetProcAddress(hIpHlpApi, 'GetPerTcpConnectionEStats');
+ @_SetPerTcpConnectionEStats := GetProcAddress(hIpHlpApi, 'SetPerTcpConnectionEStats');
+ @_GetPerTcp6ConnectionEStats := GetProcAddress(hIpHlpApi, 'GetPerTcp6ConnectionEStats');
+ @_SetPerTcp6ConnectionEStats := GetProcAddress(hIpHlpApi, 'SetPerTcp6ConnectionEStats');
+ end;
+ Result := True;
+end;
+
+{ converts numerical MAC-address to ww-xx-yy-zz string }
+function MacAddr2Str(const aMacAddr: TMacAddr; aSize: integer): string;
+var
+ i: integer;
+begin
+ if (aSize = 0) then
+ begin
+ Result := '00-00-00-00-00-00';
+ Exit;
+ end
+ else
+ Result := '';
+
+ for i := 1 to aSize do
+ begin
+ Result := Result + IntToHex(aMacAddr[i], 2);
+ if (i <> aSize) then
+ Result := Result + '-';
+ end;
+end;
+
+function GetExtendedTcpTable; external iphlpapilib name 'GetExtendedTcpTable';
+function GetExtendedUdpTable; external iphlpapilib name 'GetExtendedUdpTable';
+
+function GetPerTcpConnectionEStats(Row: PMIB_TCPROW; EstatsType: TCP_ESTATS_TYPE;
+ Rw: PUCHAR; RwVersion: ULONG; RwSize: ULONG; Ros: PUCHAR; RosVersion: ULONG;
+ RosSize: ULONG; Rod: PUCHAR; RodVersion: ULONG; RodSize: ULONG): ULONG;
+begin
+ if (CheckStubsLoaded) then
+ Result := _GetPerTcpConnectionEStats(Row, EstatsType, Rw, RwVersion, RwSize, Ros,
+ RosVersion, RosSize, Rod, RodVersion, RodSize)
+ else
+ Result := 0;
+end;
+
+function SetPerTcpConnectionEStats(Row: PMIB_TCPROW; EstatsType: TCP_ESTATS_TYPE;
+ Rw: PUCHAR; RwVersion: ULONG; RwSize: ULONG; Offset: ULONG): ULONG;
+begin
+ if (CheckStubsLoaded) then
+ Result := _SetPerTcpConnectionEStats(Row, EstatsType, Rw, RwVersion, RwSize, Offset)
+ else
+ Result := 0;
+end;
+
+function GetPerTcp6ConnectionEStats(Row: PMIB_TCP6ROW; EstatsType: TCP_ESTATS_TYPE;
+ Rw: PUCHAR; RwVersion: ULONG; RwSize: ULONG; Ros: PUCHAR; RosVersion: ULONG;
+ RosSize: ULONG; Rod: PUCHAR; RodVersion: ULONG; RodSize: ULONG): ULONG;
+begin
+ if (CheckStubsLoaded) then
+ Result := _GetPerTcp6ConnectionEStats(Row, EstatsType, Rw, RwVersion, RwSize, Ros,
+ RosVersion, RosSize, Rod, RodVersion, RodSize)
+ else
+ Result := 0;
+end;
+
+function SetPerTcp6ConnectionEStats(Row: PMIB_TCP6ROW; EstatsType: TCP_ESTATS_TYPE;
+ Rw: PUCHAR; RwVersion: ULONG; RwSize: ULONG; Offset: ULONG): ULONG;
+begin
+ if (CheckStubsLoaded) then
+ Result := _SetPerTcp6ConnectionEStats(Row, EstatsType, Rw, RwVersion, RwSize, Offset)
+ else
+ Result := 0;
+end;
+
+end.
diff --git a/EvilWorks.Api.OpenSSL.pas b/EvilWorks.Api.OpenSSL.pas
new file mode 100644
index 0000000..121fd26
--- /dev/null
+++ b/EvilWorks.Api.OpenSSL.pas
@@ -0,0 +1,416 @@
+//
+// EvilLibrary by Vedran Vuk 2010-2012
+//
+// Name: EvilWorks.Api.OpenSSL
+// Description: Basic imports from OpenSSL library and a few helpers.
+// File last change date: October 1st. 2012
+// File version: Dev 0.0.0
+// Licence: Free.
+//
+
+unit EvilWorks.Api.OpenSSL;
+
+interface
+
+uses
+ Winapi.Windows,
+ EvilWorks.Api.Winsock2;
+
+const
+ ssleay32 = 'ssleay32.dll';
+ libeay32 = 'libeay32.dll';
+
+const
+ SSL_ERROR_NONE = 0;
+ SSL_ERROR_SSL = 1;
+ SSL_ERROR_WANT_READ = 2;
+ SSL_ERROR_WANT_WRITE = 3;
+ SSL_ERROR_WANT_X509_LOOKUP = 4;
+ SSL_ERROR_SYSCALL = 5;
+ SSL_ERROR_ZERO_RETURN = 6;
+ SSL_ERROR_WANT_CONNECT = 7;
+ SSL_ERROR_WANT_ACCEPT = 8;
+
+ SSL_ST_CONNECT = $1000;
+ SSL_ST_ACCEPT = $2000;
+ SSL_ST_MASK = $0FFF;
+ SSL_ST_INIT = SSL_ST_CONNECT or SSL_ST_ACCEPT;
+ SSL_ST_BEFORE = $4000;
+ SSL_ST_OK = $03;
+ SSL_ST_RENEGOTIATE = $04 or SSL_ST_INIT;
+
+ SSL_OP_ALL = $80000BFF;
+
+ SSL_OP_NO_SSLv2 = $01000000;
+ SSL_OP_NO_SSLv3 = $02000000;
+ SSL_OP_NO_TLSv1 = $04000000;
+ SSL_OP_NO_TLSv1_2 = $08000000;
+ SSL_OP_NO_TLSv1_1 = $10000000;
+
+ SSL_CTRL_OPTIONS = 32;
+ SSL_CTRL_MODE = 33;
+
+ SSL_MODE_AUTO_RETRY = $00000004;
+
+ SSL_VERIFY_NONE = $00;
+ SSL_VERIFY_PEER = $01;
+ SSL_VERIFY_FAIL_IF_NO_PEER_CERT = $02;
+ SSL_VERIFY_CLIENT_ONCE = $04;
+
+ X509_FILETYPE_PEM = 1;
+ X509_FILETYPE_ASN1 = 2;
+ X509_FILETYPE_DEFAULT = 3;
+
+ SSL_FILETYPE_ASN1 = X509_FILETYPE_ASN1;
+ SSL_FILETYPE_PEM = X509_FILETYPE_PEM;
+
+ BIO_NOCLOSE = $00;
+ BIO_CLOSE = $01;
+
+ BIO_CTRL_RESET = 1; // opt - rewind/zero etc */
+ BIO_CTRL_EOF = 2; // opt - are we at the eof */
+ BIO_CTRL_INFO = 3; // opt - extra tit-bits */
+ BIO_CTRL_SET = 4; // man - set the 'IO' type */
+ BIO_CTRL_GET = 5; // man - get the 'IO' type */
+ BIO_CTRL_PUSH = 6; // opt - internal, used to signify change */
+ BIO_CTRL_POP = 7; // opt - internal, used to signify change */
+ BIO_CTRL_GET_CLOSE = 8; // man - set the 'close' on free */
+ BIO_CTRL_SET_CLOSE = 9; // man - set the 'close' on free */
+ BIO_CTRL_PENDING = 10; // opt - is their more data buffered */
+ BIO_CTRL_FLUSH = 11; // opt - 'flush' buffered output */
+ BIO_CTRL_DUP = 12; // man - extra stuff for 'duped' BIO */
+ BIO_CTRL_WPENDING = 13; // opt - number of bytes still to write */
+
+ BIO_FLAGS_READ = $01;
+ BIO_FLAGS_WRITE = $02;
+ BIO_FLAGS_IO_SPECIAL = $04;
+ BIO_FLAGS_RWS = BIO_FLAGS_READ or BIO_FLAGS_WRITE or BIO_FLAGS_IO_SPECIAL;
+ BIO_FLAGS_SHOULD_RETRY = $08;
+
+ SSL_NOTHING = 1;
+ SSL_WRITING = 2;
+ SSL_READING = 3;
+ SSL_X509_LOOKUP = 4;
+
+type
+ // lol dem all pointers
+ SslPtr = Pointer;
+ PSSL = SslPtr;
+ PSSL_CTX = SslPtr;
+ PSSL_METHOD = SslPtr;
+ PBIO = SslPtr;
+ PBIO_METHOD = SslPtr;
+ X509 = SslPtr;
+ PX509 = ^X509;
+ X509_STORE_CTX = SslPtr;
+ X509_NAME = SslPtr; // record!
+ PSSL_CIPHER = SslPtr;
+
+ TVerify_Callback = function(ok: integer; store: Pointer): integer;
+
+const
+ X509_V_OK = 0;
+
+function SSL_library_init: integer; cdecl; external ssleay32 name 'SSL_library_init';
+procedure SSL_load_error_strings; cdecl; external ssleay32 name 'SSL_load_error_strings';
+function SSL_state_string_long(const s: PSSL): pansichar; cdecl; external ssleay32 name 'SSL_state_string_long';
+
+function SSL_new(pCTX: PSSL_CTX): PSSL; cdecl; external ssleay32 name 'SSL_new';
+procedure SSL_free(aSSL: PSSL); cdecl; external ssleay32 name 'SSL_free';
+
+function SSL_state(const ssl: PSSL): integer; cdecl; external ssleay32 name 'SSL_state';
+function SSL_get_error(const s: PSSL; ret_code: integer): integer; cdecl; external ssleay32 name 'SSL_get_error';
+
+function SSL_connect(ssl: PSSL): integer; cdecl; external ssleay32 name 'SSL_connect';
+function SSL_accept(ssl: PSSL): integer; cdecl; external ssleay32 name 'SSL_accept';
+function SSL_read(ssl: PSSL; buf: Pointer; num: integer): integer; cdecl; external ssleay32 name 'SSL_read';
+function SSL_write(ssl: PSSL; const buf: Pointer; num: integer): integer; cdecl; external ssleay32 name 'SSL_write';
+function SSL_pending(ssl: PSSL): integer; cdecl; external ssleay32 name 'SSL_pending';
+function SSL_shutdown(ssl: PSSL): integer; cdecl; external ssleay32 name 'SSL_shutdown';
+function SSL_peek(s: PSSL; buf: Pointer; num: integer): integer; cdecl; external ssleay32 name 'SSL_peek';
+
+function SSL_set_fd(ssl: PSSL; fd: integer): integer; cdecl; external ssleay32 name 'SSL_set_fd';
+procedure SSL_set_connect_state(s: PSSL); cdecl; external ssleay32 name 'SSL_set_connect_state';
+procedure SSL_set_accept_state(s: PSSL); cdecl; external ssleay32 name 'SSL_set_accept_state';
+procedure SSL_set_bio(s: PSSL; rbio, wbio: PBIO); cdecl; external ssleay32 name 'SSL_set_bio';
+procedure SSL_set_shutdown(s: PSSL; mode: integer); cdecl; external ssleay32 name 'SSL_set_shutdown';
+function SSL_get_shutdown(s: PSSL): integer; cdecl; external ssleay32 name 'SSL_get_shutdown';
+
+function SSL_want(const s: PSSL): integer; cdecl; external ssleay32 name 'SSL_want';
+
+function SSL_get_peer_certificate(const ssl: PSSL): PX509;
+cdecl external ssleay32 name 'SSL_get_peer_certificate';
+
+function SSL_CTX_new(pMeth: PSSL_METHOD): PSSL_CTX; cdecl; external ssleay32 name 'SSL_CTX_new';
+procedure SSL_CTX_free(pCTX: PSSL_CTX); cdecl; external ssleay32 name 'SSL_CTX_free';
+
+function SSL_CTX_ctrl(ctx: PSSL_CTX; cmd: integer; larg: LongInt; parg: Pointer): LongInt; cdecl;
+ external ssleay32 name 'SSL_CTX_ctrl';
+function SSL_CTX_set_cipher_list(ctx: PSSL_CTX; const str: pansichar): integer; cdecl;
+ external ssleay32 name 'SSL_CTX_set_cipher_list';
+
+//procedure SSL_CTX_set_default_passwd_cb(ctx: PSSL_CTX, pem_password_cb * cb); cdecl;
+// external ssleay32 name 'SSL_CTX_set_default_passwd_cb';
+//procedure SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX * ctx, void * u); cdecl;
+// external ssleay32 name 'SSL_CTX_set_default_passwd_cb_userdata';
+
+procedure SSL_CTX_set_default_passwd_cb(ctx: PSSL_CTX; cb: pointer); cdecl;
+ external ssleay32 name 'SSL_CTX_set_default_passwd_cb';
+procedure SSL_CTX_set_default_passwd_cb_userdata(ctx: PSSL_CTX; u: pointer); cdecl;
+ external ssleay32 name 'SSL_CTX_set_default_passwd_cb_userdata';
+
+procedure SSL_CTX_set_verify(ctx: PSSL_CTX; mode: integer; callback: TVerify_Callback); cdecl;
+ external ssleay32 name 'SSL_CTX_set_verify';
+procedure SSL_CTX_set_verify_depth(ctx: PSSL_CTX; depth: integer); cdecl;
+ external ssleay32 name 'SSL_CTX_set_verify_depth';
+
+function SSL_CTX_use_RSAPrivateKey_file(ctx: PSSL_CTX; const filename: pansichar; typ: integer): integer;
+ cdecl; external ssleay32 name 'SSL_CTX_use_RSAPrivateKey_file';
+function SSL_CTX_use_certificate_file(pCTX: PSSL_CTX; const aFile: pansichar; typ: integer): integer; cdecl;
+ external ssleay32 name 'SSL_CTX_use_certificate_file';
+function SSL_CTX_load_verify_locations(ctx: PSSL_CTX; const CAFile, CAPath: pansichar): integer; cdecl;
+ external ssleay32 name 'SSL_CTX_load_verify_locations';
+function SSL_CTX_set_default_verify_paths(ctx: PSSL_CTX): integer; cdecl;
+ external ssleay32 name 'SSL_CTX_set_default_verify_paths';
+function SSL_CTX_use_certificate_chain_file(ctx: PSSL_CTX; const aFile: pansichar): integer; cdecl;
+ external ssleay32 name 'SSL_CTX_use_certificate_chain_file';
+function SSL_CTX_use_PrivateKey_file(ssl: PSSL; const aFile: pansichar; typ: integer): integer; cdecl;
+ external ssleay32 name 'SSL_CTX_use_PrivateKey_file';
+function SSL_CTX_check_private_key(const ctx: PSSL_CTX): integer; cdecl;
+ external ssleay32 name 'SSL_CTX_check_private_key';
+
+function SSL_get_current_cipher(const s: PSSL): PSSL_CIPHER; cdecl; external ssleay32 name 'SSL_get_current_cipher';
+function SSL_CIPHER_get_name(const c: PSSL_CIPHER): pansichar; cdecl; external ssleay32 name 'SSL_CIPHER_get_name';
+
+procedure SSL_set_verify_result(ssl: PSSL; v: long); cdecl; external ssleay32 name 'SSL_set_verify_result';
+function SSL_get_verify_result(ssl: PSSL): long; cdecl; external ssleay32 name 'SSL_get_verify_result';
+
+function SSLv2_method: PSSL_METHOD; cdecl; external ssleay32 name 'SSLv2_method';
+function SSLv23_method: PSSL_METHOD; cdecl; external ssleay32 name 'SSLv23_method';
+function SSLv3_method: PSSL_METHOD; cdecl; external ssleay32 name 'SSLv3_method';
+function TLSv1_method: PSSL_METHOD; cdecl; external ssleay32 name 'TLSv1_method';
+
+function BIO_new(b: PBIO_METHOD): PBIO; cdecl; external libeay32 name 'BIO_new';
+function BIO_new_socket(sock, close_flag: integer): PBIO; cdecl; external libeay32 name 'BIO_new_socket';
+function BIO_free(b: PBIO): integer; cdecl; external libeay32 name 'BIO_free';
+
+function BIO_push(b: PBIO; append: PBIO): PBIO; cdecl; external libeay32 name 'BIO_push';
+function BIO_pop(b: PBIO): PBIO; cdecl; external libeay32 name 'BIO_pop';
+
+function BIO_read(b: PBIO; buf: Pointer; len: integer): integer; cdecl; external libeay32 name 'BIO_read';
+function BIO_write(b: PBIO; const buf: Pointer; len: integer): integer; cdecl; external libeay32 name 'BIO_write';
+function BIO_ctrl(b: PBIO; cmd: integer; larg: long; parg: Pointer): long; cdecl; external libeay32 name 'BIO_ctrl';
+
+function BIO_s_mem: PBIO_METHOD; cdecl; external libeay32 name 'BIO_s_mem';
+function BIO_s_socket: PBIO_METHOD; cdecl; external libeay32 name 'BIO_s_socket';
+
+procedure BIO_set_flags(b: PBIO; flags: integer); cdecl; external libeay32 name 'BIO_set_flags';
+function BIO_test_flags(const b: PBIO; flags: integer): integer; cdecl; external libeay32 name 'BIO_test_flags';
+procedure BIO_clear_flags(b: PBIO; flags: integer); cdecl; external libeay32 name 'BIO_clear_flags';
+
+function X509_STORE_CTX_get_current_cert(ctx: X509_STORE_CTX): X509; cdecl;
+ external libeay32 name 'X509_STORE_CTX_get_current_cert';
+function X509_STORE_CTX_get_error_depth(ctx: X509_STORE_CTX): integer; cdecl;
+ external libeay32 name 'X509_STORE_CTX_get_error_depth';
+function X509_STORE_CTX_get_error(ctx: X509_STORE_CTX): integer; cdecl;
+ external libeay32 name 'X509_STORE_CTX_get_error';
+
+function X509_NAME_oneline(a: X509_NAME; buf: pansichar; size: integer): pansichar; cdecl;
+ external libeay32 name 'X509_NAME_oneline';
+
+function X509_get_issuer_name(a: X509): X509_NAME; cdecl; external libeay32 name 'X509_get_issuer_name';
+function X509_get_subject_name(a: X509): X509_NAME; cdecl; external libeay32 name 'X509_get_issuer_name';
+
+function X509_verify_cert_error_string(n: LongInt): pansichar; cdecl;
+ external libeay32 name 'X509_verify_cert_error_string';
+
+procedure ERR_print_errors(bp: PBIO); cdecl; external libeay32 name 'ERR_print_errors';
+procedure ERR_print_errors_fp(aFilePointer: THandle); cdecl; external libeay32 name 'ERR_print_errors_fp';
+
+procedure ERR_free_strings; cdecl; external libeay32 name 'ERR_free_strings';
+function ERR_get_error: LongInt; cdecl; external libeay32 name 'ERR_get_error';
+function ERR_error_string(e: LongInt; buf: pansichar): pansichar; cdecl; external libeay32 name 'ERR_error_string';
+procedure ERR_error_string_n(e: LongInt; buf: pansichar; len: longword); cdecl; external libeay32 name 'ERR_error_string_n';
+
+function ERR_lib_error_string(e: LongInt): pansichar; cdecl; external libeay32 name 'ERR_lib_error_string';
+function ERR_func_error_string(e: LongInt): pansichar; cdecl; external libeay32 name 'ERR_func_error_string';
+function ERR_reason_error_string(e: LongInt): pansichar; cdecl; external libeay32 name 'ERR_reason_error_string';
+
+procedure OPENSSL_add_all_algorithms_noconf; cdecl; external libeay32 name 'OPENSSL_add_all_algorithms_noconf';
+procedure OPENSSL_add_all_algorithms_conf; cdecl; external libeay32 name 'OPENSSL_add_all_algorithms_conf';
+procedure OpenSSL_add_all_digests; cdecl; external libeay32 name 'OpenSSL_add_all_digests';
+procedure OpenSSL_add_all_ciphers; cdecl; external libeay32 name 'OpenSSL_add_all_ciphers';
+procedure EVP_cleanup; cdecl; external libeay32 name 'EVP_cleanup';
+
+procedure CRYPTO_free(p: Pointer); cdecl; external libeay32 name 'CRYPTO_free';
+
+{ Macros }
+function SSL_get_state(ssl: PSSL): integer;
+function SSL_is_init_finished(ssl: PSSL): boolean;
+function SSL_in_init(ssl: PSSL): boolean;
+function SSL_in_before(ssl: PSSL): boolean;
+function SSL_in_connect_init(ssl: PSSL): boolean;
+function SSL_in_accept_init(ssl: PSSL): boolean;
+
+function SSL_want_nothing(const s: PSSL): boolean;
+function SSL_want_read(const s: PSSL): boolean;
+function SSL_want_write(const s: PSSL): boolean;
+function SSL_want_x509_lookup(const s: PSSL): boolean;
+
+function BIO_pending(b: PBIO): integer;
+
+function BIO_should_read(const b: PBIO): integer;
+function BIO_should_write(const b: PBIO): integer;
+function BIO_should_io_special(const b: PBIO): integer;
+function BIO_retry_type(const b: PBIO): integer;
+function BIO_should_retry(const b: PBIO): integer;
+
+procedure OPENSSL_free(p: Pointer);
+
+function SSL_CTX_set_options(ctx: PSSL_CTX; op: LongInt): LongInt;
+
+{ ============================================================ }
+{ ====================== Helper types ======================== }
+{ ============================================================ }
+
+type
+ TSSLMethod = (smSSLv2, smSSLv23, smSSLv3, smTLSv1);
+
+{ ============================================================ }
+{ ==================== Helper functions ====================== }
+{ ============================================================ }
+
+{ Extra 'macros' }
+function SSL_in_renegotiation(ssl: PSSL): boolean;
+
+{ Error functions }
+function GetSSLErrorText(const aErr: integer): string;
+function GetLastOpenSSLErrorText: string;
+
+implementation
+
+function SSL_get_state(ssl: PSSL): integer;
+begin
+ Result := SSL_state(ssl);
+end;
+
+function SSL_is_init_finished(ssl: PSSL): boolean;
+begin
+ Result := (SSL_state(ssl) = SSL_ST_OK);
+end;
+
+function SSL_in_init(ssl: PSSL): boolean;
+begin
+ Result := (SSL_state(ssl) and SSL_ST_INIT <> 0);
+end;
+
+function SSL_in_before(ssl: PSSL): boolean;
+begin
+ Result := (SSL_state(ssl) and SSL_ST_BEFORE <> 0);
+end;
+
+function SSL_in_connect_init(ssl: PSSL): boolean;
+begin
+ Result := (SSL_state(ssl) and SSL_ST_CONNECT <> 0);
+end;
+
+function SSL_in_accept_init(ssl: PSSL): boolean;
+begin
+ Result := (SSL_state(ssl) and SSL_ST_ACCEPT <> 0);
+end;
+
+function SSL_want_nothing(const s: PSSL): boolean;
+begin
+ Result := (SSL_want(s) = SSL_NOTHING);
+end;
+
+function SSL_want_read(const s: PSSL): boolean;
+begin
+ Result := (SSL_want(s) = SSL_READING);
+end;
+
+function SSL_want_write(const s: PSSL): boolean;
+begin
+ Result := (SSL_want(s) = SSL_WRITING);
+end;
+
+function SSL_want_x509_lookup(const s: PSSL): boolean;
+begin
+ Result := (SSL_want(s) = SSL_X509_LOOKUP);
+end;
+
+function BIO_pending(b: PBIO): integer;
+begin
+ Result := BIO_ctrl(b, BIO_CTRL_PENDING, 0, nil);
+end;
+
+function BIO_should_read(const b: PBIO): integer;
+begin
+ Result := BIO_test_flags(b, BIO_FLAGS_READ);
+end;
+
+function BIO_should_write(const b: PBIO): integer;
+begin
+ Result := BIO_test_flags(b, BIO_FLAGS_WRITE);
+end;
+
+function BIO_should_io_special(const b: PBIO): integer;
+begin
+ Result := BIO_test_flags(b, BIO_FLAGS_IO_SPECIAL);
+end;
+
+function BIO_retry_type(const b: PBIO): integer;
+begin
+ Result := BIO_test_flags(b, BIO_FLAGS_RWS);
+end;
+
+function BIO_should_retry(const b: PBIO): integer;
+begin
+ Result := BIO_test_flags(b, BIO_FLAGS_SHOULD_RETRY);
+end;
+
+procedure OPENSSL_free(p: Pointer);
+begin
+ CRYPTO_free(p);
+end;
+
+function SSL_CTX_set_options(ctx: PSSL_CTX; op: LongInt): LongInt;
+begin
+ Result := SSL_CTX_ctrl(ctx, SSL_CTRL_OPTIONS, op, nil);
+end;
+
+function SSL_in_renegotiation(ssl: PSSL): boolean;
+begin
+ Result := (SSL_state(ssl) and SSL_ST_RENEGOTIATE <> 0);
+end;
+
+function GetLastOpenSSLErrorText: string;
+begin
+ Result := string(ERR_error_string(ERR_get_error, nil));
+end;
+
+function GetSSLErrorText(const aErr: integer): string;
+begin
+ case aErr of
+ SSL_ERROR_NONE:
+ Result := 'SSL_ERROR_NONE';
+ SSL_ERROR_SSL:
+ Result := 'SSL_ERROR_SSL';
+ SSL_ERROR_WANT_READ:
+ Result := 'SSL_ERROR_WANT_READ';
+ SSL_ERROR_WANT_WRITE:
+ Result := 'SSL_ERROR_WANT_WRITE';
+ SSL_ERROR_WANT_X509_LOOKUP:
+ Result := 'SSL_ERROR_WANT_X509_LOOKUP';
+ SSL_ERROR_SYSCALL:
+ Result := 'SSL_ERROR_SYSCALL';
+ SSL_ERROR_ZERO_RETURN:
+ Result := 'SSL_ERROR_ZERO_RETURN';
+ SSL_ERROR_WANT_CONNECT:
+ Result := 'SSL_ERROR_WANT_CONNECT';
+ SSL_ERROR_WANT_ACCEPT:
+ Result := 'SSL_ERROR_WANT_ACCEPT';
+ end;
+end;
+
+end.
diff --git a/EvilWorks.Api.PowrProf.pas b/EvilWorks.Api.PowrProf.pas
new file mode 100644
index 0000000..bba6dcf
--- /dev/null
+++ b/EvilWorks.Api.PowrProf.pas
@@ -0,0 +1,72 @@
+unit EvilWorks.Api.PowrProf;
+
+interface
+
+uses
+ WinApi.Windows;
+
+type
+
+{$EXTERNALSYM POWER_DATA_ACCESSOR}
+ POWER_DATA_ACCESSOR = (
+ // Used by read/write and enumeration engines
+ ACCESS_AC_POWER_SETTING_INDEX = 0,
+ ACCESS_DC_POWER_SETTING_INDEX,
+ ACCESS_FRIENDLY_NAME,
+ ACCESS_DESCRIPTION,
+ ACCESS_POSSIBLE_POWER_SETTING,
+ ACCESS_POSSIBLE_POWER_SETTING_FRIENDLY_NAME,
+ ACCESS_POSSIBLE_POWER_SETTING_DESCRIPTION,
+ ACCESS_DEFAULT_AC_POWER_SETTING,
+ ACCESS_DEFAULT_DC_POWER_SETTING,
+ ACCESS_POSSIBLE_VALUE_MIN,
+ ACCESS_POSSIBLE_VALUE_MAX,
+ ACCESS_POSSIBLE_VALUE_INCREMENT,
+ ACCESS_POSSIBLE_VALUE_UNITS,
+ ACCESS_ICON_RESOURCE,
+ ACCESS_DEFAULT_SECURITY_DESCRIPTOR,
+ ACCESS_ATTRIBUTES,
+
+ // Used by enumeration engine.
+ ACCESS_SCHEME,
+ ACCESS_SUBGROUP,
+ ACCESS_INDIVIDUAL_SETTING,
+
+ // Used by access check
+ ACCESS_ACTIVE_SCHEME,
+ ACCESS_CREATE_SCHEME,
+
+ // Used by override ranges.
+ ACCESS_AC_POWER_SETTING_MAX,
+ ACCESS_DC_POWER_SETTING_MAX,
+ ACCESS_AC_POWER_SETTING_MIN,
+ ACCESS_DC_POWER_SETTING_MIN
+
+ );
+ PPOWER_DATA_ACCESSOR = ^POWER_DATA_ACCESSOR;
+
+const
+ powrproflib = 'powrprof.dll';
+
+{$EXTERNALSYM PowerEnumerate}
+function PowerEnumerate(RootPowerKey: HKEY;
+ SchemeGuid: PGUID;
+ SubGroupOfPowerSettingsGuid: PGUID;
+ AccessFlags: POWER_DATA_ACCESSOR;
+ Index: ULONG;
+ Buffer: PUCHAR;
+ var BufferSize: DWORD
+ ): DWORD; stdcall; external powrproflib name 'PowerEnumerate';
+
+{$EXTERNALSYM PowerReadFriendlyName}
+function PowerReadFriendlyName(RootPowerKey: HKEY;
+ SchemeGuid: PGUID;
+ SubGroupOfPowerSettingsGuid: PGUID;
+ PowerSettingGuid: PGUID;
+ Buffer: PUCHAR;
+ var BufferSize: DWORD
+ ): DWORD; stdcall; external powrproflib name 'PowerReadFriendlyName';
+
+implementation
+
+end.
diff --git a/EvilWorks.Api.TcpEStats.pas b/EvilWorks.Api.TcpEStats.pas
new file mode 100644
index 0000000..ca2c20e
--- /dev/null
+++ b/EvilWorks.Api.TcpEStats.pas
@@ -0,0 +1,364 @@
+unit EvilWorks.Api.TcpEStats;
+
+interface
+
+uses
+ WinApi.Windows;
+
+type
+
+ //
+ // Please don't change the order of this enum. The order defined in this
+ // enum needs to match the order in EstatsToTcpObjectMappingTable.
+ //
+
+ TCP_ESTATS_TYPE = (
+ TcpConnectionEstatsSynOpts,
+ TcpConnectionEstatsData,
+ TcpConnectionEstatsSndCong,
+ TcpConnectionEstatsPath,
+ TcpConnectionEstatsSendBuff,
+ TcpConnectionEstatsRec,
+ TcpConnectionEstatsObsRec,
+ TcpConnectionEstatsBandwidth,
+ TcpConnectionEstatsFineRtt,
+ TcpConnectionEstatsMaximum
+ );
+ PTCP_ESTATS_TYPE = ^TCP_ESTATS_TYPE;
+
+ //
+ // TCP_BOOLEAN_OPTIONAL
+ //
+ // Define the states that a caller can specify when updating a boolean field.
+ //
+
+ TCP_BOOLEAN_OPTIONAL = (
+ TcpBoolOptDisabled = 0,
+ TcpBoolOptEnabled,
+ TcpBoolOptUnchanged = - 1
+ );
+ PTCP_BOOLEAN_OPTIONAL = ^TCP_BOOLEAN_OPTIONAL;
+
+ //
+ // TCP_ESTATS_SYN_OPTS_ROS
+ //
+ // Define extended SYN-exchange information maintained for TCP connections.
+ //
+
+ TCP_ESTATS_SYN_OPTS_ROS_v0 = record
+ ActiveOpen: BOOLEAN;
+ MssRcvd: ULONG;
+ MssSent: ULONG;
+ end;
+ PTCP_ESTATS_SYN_OPTS_ROS_v0 = ^TCP_ESTATS_SYN_OPTS_ROS_v0;
+
+ //
+ // TCP_SOFT_ERROR
+ //
+ // Enumerate the non-fatal errors recorded on each connection.
+ //
+
+ TCP_SOFT_ERROR = (
+ TcpErrorNone = 0,
+ TcpErrorBelowDataWindow,
+ TcpErrorAboveDataWindow,
+ TcpErrorBelowAckWindow,
+ TcpErrorAboveAckWindow,
+ TcpErrorBelowTsWindow,
+ TcpErrorAboveTsWindow,
+ TcpErrorDataChecksumError,
+ TcpErrorDataLengthError,
+ TcpErrorMaxSoftError
+ );
+ PTCP_SOFT_ERROR = ^TCP_SOFT_ERROR;
+
+ //
+ // TCP_ESTATS_DATA_ROD
+ //
+ // Define extended data-transfer information for TCP connections.
+ //
+
+ TCP_ESTATS_DATA_ROD_v0 = record
+ DataBytesOut: ULONG64;
+ DataSegsOut: ULONG64;
+ DataBytesIn: ULONG64;
+ DataSegsIn: ULONG64;
+ SegsOut: ULONG64;
+ SegsIn: ULONG64;
+ SoftErrors: ULONG;
+ SoftErrorReason: ULONG;
+ SndUna: ULONG;
+ SndNxt: ULONG;
+ SndMax: ULONG;
+ ThruBytesAcked: ULONG64;
+ RcvNext: ULONG;
+ ThruBytesReceived: ULONG64;
+ end;
+ PTCP_ESTATS_DATA_ROD_v0 = ^TCP_ESTATS_DATA_ROD_v0;
+
+ //
+ // TCP_ESTATS_DATA_RW
+ //
+ // Define structure for enabling extended data-transfer information.
+ //
+
+ TCP_ESTATS_DATA_RW_v0 = record
+ EnableCollection: BOOLEAN;
+ end;
+ PTCP_ESTATS_DATA_RW_v0 = ^TCP_ESTATS_DATA_RW_v0;
+
+ //
+ // TCP_ESTATS_SND_CONG_ROD
+ //
+ // Define extended sender-congestion information for TCP connections.
+ //
+
+ TCP_ESTATS_SND_CONG_ROD_v0 = record
+ SndLimTransRwin: ULONG;
+ SndLimTimeRwin: ULONG;
+ SndLimBytesRwin: SIZE_T;
+ SndLimTransCwnd: ULONG;
+ SndLimTimeCwnd: ULONG;
+ SndLimBytesCwnd: SIZE_T;
+ SndLimTransSnd: ULONG;
+ SndLimTimeSnd: ULONG;
+ SndLimBytesSnd: SIZE_T;
+ SlowStart: ULONG;
+ CongAvoid: ULONG;
+ OtherReductions: ULONG;
+ CurCwnd: ULONG;
+ MaxSsCwnd: ULONG;
+ MaxCaCwnd: ULONG;
+ CurSsthresh: ULONG;
+ MaxSsthresh: ULONG;
+ MinSsthresh: ULONG;
+ end;
+ PTCP_ESTATS_SND_CONG_ROD_v0 = ^TCP_ESTATS_SND_CONG_ROD_v0;
+
+ //
+ // TCP_ESTATS_SND_CONG_ROS
+ //
+ // Define static extended sender-congestion information for TCP connections.
+
+ TCP_ESTATS_SND_CONG_ROS_v0 = record
+ LimCwnd: ULONG;
+ end;
+ PTCP_ESTATS_SND_CONG_ROS_v0 = ^TCP_ESTATS_SND_CONG_ROS_v0;
+
+ //
+ // TCP_ESTATS_SND_CONG_RW
+ //
+ // Define structure for enabling extended sender-congestion information.
+ //
+
+ TCP_ESTATS_SND_CONG_RW = record
+ EnableCollection: BOOLEAN;
+ end;
+ PTCP_ESTATS_SND_CONG_RW = ^TCP_ESTATS_SND_CONG_RW;
+
+ //
+ // TCP_ESTATS_PATH_ROD
+ //
+ // Define extended path-measurement information for TCP connections.
+ //
+
+ TCP_ESTATS_PATH_ROD_v0 = record
+ FastRetran: ULONG;
+ Timeouts: ULONG;
+ SubsequentTimeouts: ULONG;
+ CurTimeoutCount: ULONG;
+ AbruptTimeouts: ULONG;
+ PktsRetrans: ULONG;
+ BytesRetrans: ULONG;
+ DupAcksIn: ULONG;
+ SacksRcvd: ULONG;
+ SackBlocksRcvd: ULONG;
+ CongSignals: ULONG;
+ PreCongSumCwnd: ULONG;
+ PreCongSumRtt: ULONG;
+ PostCongSumRtt: ULONG;
+ PostCongCountRtt: ULONG;
+ EcnSignals: ULONG;
+ EceRcvd: ULONG;
+ SendStall: ULONG;
+ QuenchRcvd: ULONG;
+ RetranThresh: ULONG;
+ SndDupAckEpisodes: ULONG;
+ SumBytesReordered: ULONG;
+ NonRecovDa: ULONG;
+ NonRecovDaEpisodes: ULONG;
+ AckAfterFr: ULONG;
+ DsackDups: ULONG;
+ SampleRtt: ULONG;
+ SmoothedRtt: ULONG;
+ RttVar: ULONG;
+ MaxRtt: ULONG;
+ MinRtt: ULONG;
+ SumRtt: ULONG;
+ CountRtt: ULONG;
+ CurRto: ULONG;
+ MaxRto: ULONG;
+ MinRto: ULONG;
+ CurMss: ULONG;
+ MaxMss: ULONG;
+ MinMss: ULONG;
+ SpuriousRtoDetections: ULONG;
+
+ end;
+ PTCP_ESTATS_PATH_ROD_v0 = ^TCP_ESTATS_PATH_ROD_v0;
+
+ //
+ // TCP_ESTATS_PATH_ROS
+ //
+ // Define structure for enabling path-measurement information.
+ //
+
+ TCP_ESTATS_PATH_RW_v0 = record
+ EnableCollection: BOOLEAN;
+ end;
+ PTCP_ESTATS_PATH_RW_v0 = ^TCP_ESTATS_PATH_RW_v0;
+
+ //
+ // TCP_ESTATS_SEND_BUFF_ROD
+ //
+ // Define extended output-queuing information for TCP connections.
+ //
+
+ TCP_ESTATS_SEND_BUFF_ROD_v0 = record
+ CurRetxQueue: SIZE_T;
+ MaxRetxQueue: SIZE_T;
+ CurAppWQueue: SIZE_T;
+ MaxAppWQueue: SIZE_T;
+ end;
+ PTCP_ESTATS_SEND_BUFF_ROD_v0 = ^TCP_ESTATS_SEND_BUFF_ROD_v0;
+
+ //
+ // TCP_ESTATS_SEND_BUFF_RW
+ //
+ // Define structure for enabling output-queuing information.
+ //
+
+ TCP_ESTATS_SEND_BUFF_RW_v0 = record
+ EnableCollection: BOOLEAN;
+ end;
+ PTCP_ESTATS_SEND_BUFF_RW_v0 = ^TCP_ESTATS_SEND_BUFF_RW_v0;
+
+ //
+ // TCP_ESTATS_REC_ROD
+ //
+ // Define extended local-receiver information for TCP connections.
+ //
+
+ TCP_ESTATS_REC_ROD_v0 = record
+ CurRwinSent: ULONG;
+ MaxRwinSent: ULONG;
+ MinRwinSent: ULONG;
+ LimRwin: ULONG;
+ DupAckEpisodes: ULONG;
+ DupAcksOut: ULONG;
+ CeRcvd: ULONG;
+ EcnSent: ULONG;
+ EcnNoncesRcvd: ULONG;
+ CurReasmQueue: ULONG;
+ MaxReasmQueue: ULONG;
+ CurAppRQueue: SIZE_T;
+ MaxAppRQueue: SIZE_T;
+ WinScaleSent: UCHAR;
+ end;
+ PTCP_ESTATS_REC_ROD_v0 = ^TCP_ESTATS_REC_ROD_v0;
+
+ //
+ // TCP_ESTATS_REC_RW
+ //
+ // Define structure for enabling local-receiver information.
+ //
+
+ TCP_ESTATS_REC_RW_v0 = record
+ EnableCollection: BOOLEAN;
+ end;
+ PTCP_ESTATS_REC_RW_v0 = ^TCP_ESTATS_REC_RW_v0;
+
+ //
+ // TCP_ESTATS_OBS_REC_ROD
+ //
+ // Define extended remote-receiver information for TCP connections.
+ //
+
+ TCP_ESTATS_OBS_REC_ROD_v0 = record
+ CurRwinRcvd: ULONG;
+ MaxRwinRcvd: ULONG;
+ MinRwinRcvd: ULONG;
+ WinScaleRcvd: UCHAR;
+ end;
+ PTCP_ESTATS_OBS_REC_ROD_v0 = ^TCP_ESTATS_OBS_REC_ROD_v0;
+
+ //
+ // TCP_ESTATS_OBS_REC_RW
+ //
+ // Define structure for enabling remote-receiver information.
+ //
+
+ TCP_ESTATS_OBS_REC_RW_v0 = record
+ EnableCollection: BOOLEAN;
+ end;
+ PTCP_ESTATS_OBS_REC_RW_v0 = ^TCP_ESTATS_OBS_REC_RW_v0;
+
+ //
+ // TCP_ESTATS_BW_RW
+ //
+ // Define the structure for enabling bandwidth estimation for TCP connections.
+ //
+
+ TCP_ESTATS_BANDWIDTH_RW_v0 = record
+ EnableCollectionOutbound: TCP_BOOLEAN_OPTIONAL;
+ EnableCollectionInbound: TCP_BOOLEAN_OPTIONAL;
+ end;
+ PTCP_ESTATS_BANDWIDTH_RW_v0 = ^TCP_ESTATS_BANDWIDTH_RW_v0;
+
+ //
+ // TCP_ESTATS_BW_ROD
+ //
+ // Define bandwidth estimation statistics for TCP connections.
+ //
+ // Bandwidth and Instability metrics are expressed as bits per second.
+ //
+
+ TCP_ESTATS_BANDWIDTH_ROD_v0 = record
+ OutboundBandwidth: ULONG64;
+ InboundBandwidth: ULONG64;
+ OutboundInstability: ULONG64;
+ InboundInstability: ULONG64;
+ OutboundBandwidthPeaked: BOOLEAN;
+ InboundBandwidthPeaked: BOOLEAN;
+ end;
+ PTCP_ESTATS_BANDWIDTH_ROD_v0 = ^TCP_ESTATS_BANDWIDTH_ROD_v0;
+
+ //
+ // TCP_ESTATS_FINE_RTT_RW
+ //
+ // Define the structure for enabling fine-grained RTT estimation for TCP
+ // connections.
+ //
+
+ TCP_ESTATS_FINE_RTT_RW_v0 = record
+ EnableCollection: BOOLEAN;
+ end;
+ PTCP_ESTATS_FINE_RTT_RW_v0 = ^TCP_ESTATS_FINE_RTT_RW_v0;
+
+ //
+ // TCP_ESTATS_FINE_RTT_ROD
+ //
+ // Define fine-grained RTT estimation statistics for TCP connections.
+ //
+
+ TCP_ESTATS_FINE_RTT_ROD_v0 = record
+ RttVar: ULONG;
+ MaxRtt: ULONG;
+ MinRtt: ULONG;
+ SumRtt: ULONG;
+ end;
+ PTCP_ESTATS_FINE_RTT_ROD_v0 = ^TCP_ESTATS_FINE_RTT_ROD_v0;
+
+implementation
+
+end.
diff --git a/EvilWorks.Api.WinPCap.Bpf.pas b/EvilWorks.Api.WinPCap.Bpf.pas
new file mode 100644
index 0000000..0faf0d8
--- /dev/null
+++ b/EvilWorks.Api.WinPCap.Bpf.pas
@@ -0,0 +1,922 @@
+unit EvilWorks.Api.WinPCap.Bpf;
+
+// Translated from v1.4.2.11
+
+interface
+
+uses
+ WinApi.Windows,
+ EvilWorks.Api.Winsock2; // you can remove this and use WinApi.Winsock instead. Required for u_int, etc
+
+type
+ bpf_int32 = integer;
+ bpf_u_int32 = u_int;
+ pbpf_u_int32 = ^bpf_u_int32;
+
+const
+ BPF_MAXBUFSIZE = $8000;
+ BPF_MINBUFSIZE = 32;
+
+ // Current version number of filter architecture.
+ BPF_MAJOR_VERSION = 1;
+ BPF_MINOR_VERSION = 1;
+
+ //
+ // Alignment macros. BPF_WORDALIGN rounds up to the next
+ // even multiple of BPF_ALIGNMENT.
+ //
+ BPF_ALIGNMENT = sizeof(bpf_int32);
+
+ //
+ // Number of scratch memory words (for BPF_LD|BPF_MEM and BPF_ST).
+ //
+ BPF_MEMWORDS = 16;
+
+function BPF_WORDALIGN(x: integer): integer;
+
+type
+
+ //
+ // The instruction data structure.
+ //
+ pbpf_insn = ^bpf_insn;
+
+ bpf_insn = record
+ code: u_short;
+ jt: u_char;
+ jf: u_char;
+ k: bpf_u_int32;
+ end;
+
+ //
+ // Structure for "pcap_compile()", "pcap_setfilter()", etc..
+ //
+
+ { bpf_program }
+ pbpf_program = ^bpf_program;
+
+ bpf_program = record
+ bf_len: u_int;
+ bf_insns: pbpf_insn;
+ end;
+
+ //
+ // Struct return by BIOCVERSION. This represents the version number of
+ // the filter language described by the instruction encodings below.
+ // bpf understands a program iff kernel_major == filter_major &&
+ // kernel_minor >= filter_minor, that is, if the value returned by the
+ // running kernel has the same major number and a minor number equal
+ // equal to or less than the filter being downloaded. Otherwise, the
+ // results are undefined, meaning an error may be returned or packets
+ // may be accepted haphazardly.
+ // It has nothing to do with the source code version.
+ //
+ { bpf_version }
+ pbpf_version = ^bpf_version;
+
+ bpf_version = record
+ bv_major: u_short;
+ bv_minor: u_short;
+ end;
+
+const
+
+ //
+ // Data-link level type codes.
+ //
+ // Do//NOT* add new values to this list without asking
+ // "tcpdump-workers@lists.tcpdump.org" for a value. Otherwise, you run
+ // the risk of using a value that's already being used for some other
+ // purpose, and of having tools that read libpcap-format captures not
+ // being able to handle captures with your new DLT_ value, with no hope
+ // that they will ever be changed to do so (as that would destroy their
+ // ability to read captures using that value for that other purpose).
+ //
+
+ //
+ // These are the types that are the same on all platforms, and that
+ // have been defined by for ages.
+ //
+ DLT_NULL = 0; // BSD loopback encapsulation//
+ DLT_EN10MB = 1; // Ethernet (10Mb)//
+ DLT_EN3MB = 2; // Experimental Ethernet (3Mb)//
+ DLT_AX25 = 3; // Amateur Radio AX.25//
+ DLT_PRONET = 4; // Proteon ProNET Token Ring//
+ DLT_CHAOS = 5; // Chaos//
+ DLT_IEEE802 = 6; // 802.5 Token Ring//
+ DLT_ARCNET = 7; // ARCNET, with BSD-style header//
+ DLT_SLIP = 8; // Serial Line IP//
+ DLT_PPP = 9; // Point-to-point Protocol//
+ DLT_FDDI = 10; // FDDI//
+
+ //
+ // These are types that are different on some platforms, and that
+ // have been defined by for ages. We use #ifdefs to
+ // detect the BSDs that define them differently from the traditional
+ // libpcap
+ //
+ // XXX - DLT_ATM_RFC1483 is 13 in BSD/OS, and DLT_RAW is 14 in BSD/OS,
+ // but I don't know what the right #define is for BSD/OS.
+ //
+ DLT_ATM_RFC1483 = 11; // LLC-encapsulated ATM
+ DLT_RAW = 12; // raw IP
+
+ //
+ // Given that the only OS that currently generates BSD/OS SLIP or PPP
+ // is, well, BSD/OS, arguably everybody should have chosen its values
+ // for DLT_SLIP_BSDOS and DLT_PPP_BSDOS, which are 15 and 16, but they
+ // didn't. So it goes.
+ //
+ DLT_SLIP_BSDOS = 15; // BSD/OS Serial Line IP//
+ DLT_PPP_BSDOS = 16; // BSD/OS Point-to-point Protocol//
+ //
+ // 17 is used for DLT_OLD_PFLOG in OpenBSD;
+ // OBSOLETE: DLT_PFLOG is 117 in OpenBSD now as well. See below.
+ // 18 is used for DLT_PFSYNC in OpenBSD; don't use it for anything else.
+ //
+
+ DLT_ATM_CLIP = 19; // Linux Classical-IP over ATM//
+
+ //
+ // Apparently Redback uses this for its SmartEdge 400/800. I hope
+ // nobody else decided to use it, too.
+ //
+ DLT_REDBACK_SMARTEDGE = 32;
+
+ //
+ // These values are defined by NetBSD; other platforms should refrain from
+ // using them for other purposes, so that NetBSD savefiles with link
+ // types of 50 or 51 can be read as this type on all platforms.
+ //
+ DLT_PPP_SERIAL = 50; // PPP over serial with HDLC encapsulation//
+ DLT_PPP_ETHER = 51; // PPP over Ethernet//
+
+ //
+ // The Axent Raptor firewall - now the Symantec Enterprise Firewall - uses
+ // a link-layer type of 99 for the tcpdump it supplies. The link-layer
+ // header has 6 bytes of unknown data, something that appears to be an
+ // Ethernet type, and 36 bytes that appear to be 0 in at least one capture
+ // I've seen.
+ //
+ DLT_SYMANTEC_FIREWALL = 99;
+
+ //
+ // Values between 100 and 103 are used in capture file headers as
+ // link-layer types corresponding to DLT_ types that differ
+ // between platforms; don't use those values for new DLT_ new types.
+ //
+
+ //
+ // This value was defined by libpcap 0.5; platforms that have defined
+ // it with a different value should define it here with that value -
+ // a link type of 104 in a save file will be mapped to DLT_C_HDLC,
+ // whatever value that happens to be, so programs will correctly
+ // handle files with that link type regardless of the value of
+ // DLT_C_HDLC.
+ //
+ // The name DLT_C_HDLC was used by BSD/OS; we use that name for source
+ // compatibility with programs written for BSD/OS.
+ //
+ // libpcap 0.5 defined it as DLT_CHDLC; we define DLT_CHDLC as well,
+ // for source compatibility with programs written for libpcap 0.5.
+ //
+ DLT_C_HDLC = 104; // Cisco HDLC//
+ DLT_CHDLC = DLT_C_HDLC;
+
+ DLT_IEEE802_11 = 105; // IEEE 802.11 wireless//
+
+ //
+ // 106 is reserved for Linux Classical IP over ATM; it's like DLT_RAW,
+ // except when it isn't. (I.e., sometimes it's just raw IP, and
+ // sometimes it isn't.) We currently handle it as DLT_LINUX_SLL,
+ // so that we don't have to worry about the link-layer header.)
+ //
+
+ //
+ // Frame Relay; BSD/OS has a DLT_FR with a value of 11, but that collides
+ // with other values.
+ // DLT_FR and DLT_FRELAY packets start with the Q.922 Frame Relay header
+ // (DLCI, etc.).
+ //
+ DLT_FRELAY = 107;
+
+ //
+ // OpenBSD DLT_LOOP, for loopback devices; it's like DLT_NULL, except
+ // that the AF_ type in the link-layer header is in network byte order.
+ //
+ // DLT_LOOP is 12 in OpenBSD, but that's DLT_RAW in other OSes, so
+ // we don't use 12 for it in OSes other than OpenBSD.
+ //
+ DLT_LOOP = 108;
+
+ //
+ // Encapsulated packets for IPsec; DLT_ENC is 13 in OpenBSD, but that's
+ // DLT_SLIP_BSDOS in NetBSD, so we don't use 13 for it in OSes other
+ // than OpenBSD.
+ //
+ DLT_ENC = 109;
+
+ //
+ // Values between 110 and 112 are reserved for use in capture file headers
+ // as link-layer types corresponding to DLT_ types that might differ
+ // between platforms; don't use those values for new DLT_ types
+ // other than the corresponding DLT_ types.
+ //
+
+ //
+ // This is for Linux cooked sockets.
+ //
+ DLT_LINUX_SLL = 113;
+
+ //
+ // Apple LocalTalk hardware.
+ //
+ DLT_LTALK = 114;
+
+ //
+ // Acorn Econet.
+ //
+ DLT_ECONET = 115;
+
+ //
+ // Reserved for use with OpenBSD ipfilter.
+ //
+ DLT_IPFILTER = 116;
+
+ //
+ // OpenBSD DLT_PFLOG; DLT_PFLOG is 17 in OpenBSD, but that's DLT_LANE8023
+ // in SuSE 6.3, so we can't use 17 for it in capture-file headers.
+ //
+ // XXX: is there a conflict with DLT_PFSYNC 18 as well?
+ //
+ DLT_PFLOG = 117;
+
+ //
+ // Registered for Cisco-internal use.
+ //
+ DLT_CISCO_IOS = 118;
+
+ //
+ // For 802.11 cards using the Prism II chips, with a link-layer
+ // header including Prism monitor mode information plus an 802.11
+ // header.
+ //
+ DLT_PRISM_HEADER = 119;
+
+ //
+ // Reserved for Aironet 802.11 cards, with an Aironet link-layer header
+ // (see Doug Ambrisko's FreeBSD patches).
+ //
+ DLT_AIRONET_HEADER = 120;
+
+ //
+ // Reserved for Siemens HiPath HDLC.
+ //
+ DLT_HHDLC = 121;
+
+ //
+ // This is for RFC 2625 IP-over-Fibre Channel.
+ //
+ // This is not for use with raw Fibre Channel, where the link-layer
+ // header starts with a Fibre Channel frame header; it's for IP-over-FC,
+ // where the link-layer header starts with an RFC 2625 Network_Header
+ // field.
+ //
+ DLT_IP_OVER_FC = 122;
+
+ //
+ // This is for Full Frontal ATM on Solaris with SunATM, with a
+ // pseudo-header followed by an AALn PDU.
+ //
+ // There may be other forms of Full Frontal ATM on other OSes,
+ // with different pseudo-headers.
+ //
+ // If ATM software returns a pseudo-header with VPI/VCI information
+ // (and, ideally, packet type information, e.g. signalling, ILMI,
+ // LANE, LLC-multiplexed traffic, etc.), it should not use
+ // DLT_ATM_RFC1483, but should get a new DLT_ value, so tcpdump
+ // and the like don't have to infer the presence or absence of a
+ // pseudo-header and the form of the pseudo-header.
+ //
+ DLT_SUNATM = 123; // Solaris+SunATM//
+
+ //
+ // Reserved as per request from Kent Dahlgren
+ // for private use.
+ //
+ DLT_RIO = 124; // RapidIO//
+ DLT_PCI_EXP = 125; // PCI Express//
+ DLT_AURORA = 126; // Xilinx Aurora link layer//
+
+ //
+ // Header for 802.11 plus a number of bits of link-layer information
+ // including radio information, used by some recent BSD drivers as
+ // well as the madwifi Atheros driver for Linux.
+ //
+ DLT_IEEE802_11_RADIO = 127; // 802.11 plus radiotap radio header//
+
+ //
+ // Reserved for the TZSP encapsulation, as per request from
+ // Chris Waters
+ // TZSP is a generic encapsulation for any other link type,
+ // which includes a means to include meta-information
+ // with the packet, e.g. signal strength and channel
+ // for 802.11 packets.
+ //
+ DLT_TZSP = 128; // Tazmen Sniffer Protocol//
+
+ //
+ // BSD's ARCNET headers have the source host, destination host,
+ // and type at the beginning of the packet; that's what's handed
+ // up to userland via BPF.
+ //
+ // Linux's ARCNET headers, however, have a 2-byte offset field
+ // between the host IDs and the type; that's what's handed up
+ // to userland via PF_PACKET sockets.
+ //
+ // We therefore have to have separate DLT_ values for them.
+ //
+ DLT_ARCNET_LINUX = 129; // ARCNET//
+
+ //
+ // Juniper-private data link types, as per request from
+ // Hannes Gredler . The DLT_s are used
+ // for passing on chassis-internal metainformation such as
+ // QOS profiles, etc..
+ //
+ DLT_JUNIPER_MLPPP = 130;
+ DLT_JUNIPER_MLFR = 131;
+ DLT_JUNIPER_ES = 132;
+ DLT_JUNIPER_GGSN = 133;
+ DLT_JUNIPER_MFR = 134;
+ DLT_JUNIPER_ATM2 = 135;
+ DLT_JUNIPER_SERVICES = 136;
+ DLT_JUNIPER_ATM1 = 137;
+
+ //
+ // Apple IP-over-IEEE 1394, as per a request from Dieter Siegmund
+ // . The header that's presented is an Ethernet-like
+ // header:
+ //
+ // FIREWIRE_EUI64_LEN = 8;
+ // struct firewire_header {
+ // u_char firewire_dhost[FIREWIRE_EUI64_LEN];
+ // u_char firewire_shost[FIREWIRE_EUI64_LEN];
+ // u_short firewire_type;
+ // };
+ //
+ // with "firewire_type" being an Ethernet type value, rather than,
+ // for example, raw GASP frames being handed up.
+ //
+ DLT_APPLE_IP_OVER_IEEE1394 = 138;
+
+ //
+ // Various SS7 encapsulations, as per a request from Jeff Morriss
+ // and subsequent discussions.
+ //
+ DLT_MTP2_WITH_PHDR = 139; // pseudo-header with various info, followed by MTP2//
+ DLT_MTP2 = 140; // MTP2, without pseudo-header//
+ DLT_MTP3 = 141; // MTP3, without pseudo-header or MTP2//
+ DLT_SCCP = 142; // SCCP, without pseudo-header or MTP2 or MTP3//
+
+ //
+ // DOCSIS MAC frames.
+ //
+ DLT_DOCSIS = 143;
+
+ //
+ // Linux-IrDA packets. Protocol defined at http://www.irda.org.
+ // Those packets include IrLAP headers and above (IrLMP...), but
+ // don't include Phy framing (SOF/EOF/CRC & byte stuffing), because Phy
+ // framing can be handled by the hardware and depend on the bitrate.
+ // This is exactly the format you would get capturing on a Linux-IrDA
+ // interface (irdaX), but not on a raw serial port.
+ // Note the capture is done in "Linux-cooked" mode, so each packet include
+ // a fake packet header (struct sll_header). This is because IrDA packet
+ // decoding is dependant on the direction of the packet (incomming or
+ // outgoing).
+ // When/if other platform implement IrDA capture, we may revisit the
+ // issue and define a real DLT_IRDA...
+ // Jean II
+ //
+ DLT_LINUX_IRDA = 144;
+
+ //
+ // Reserved for IBM SP switch and IBM Next Federation switch.
+ //
+ DLT_IBM_SP = 145;
+ DLT_IBM_SN = 146;
+
+ //
+ // Reserved for private use. If you have some link-layer header type
+ // that you want to use within your organization, with the capture files
+ // using that link-layer header type not ever be sent outside your
+ // organization, you can use these values.
+ //
+ // No libpcap release will use these for any purpose, nor will any
+ // tcpdump release use them, either.
+ //
+ // Do//NOT* use these in capture files that you expect anybody not using
+ // your private versions of capture-file-reading tools to read; in
+ // particular, do//NOT* use them in products, otherwise you may find that
+ // people won't be able to use tcpdump, or snort, or Ethereal, or... to
+ // read capture files from your firewall/intrusion detection/traffic
+ // monitoring/etc. appliance, or whatever product uses that DLT_ value,
+ // and you may also find that the developers of those applications will
+ // not accept patches to let them read those files.
+ //
+ // Also, do not use them if somebody might send you a capture using them
+ // for//their* private type and tools using them for//your* private type
+ // would have to read them.
+ //
+ // Instead, ask "tcpdump-workers@lists.tcpdump.org" for a new DLT_ value,
+ // as per the comment above, and use the type you're given.
+ //
+ DLT_USER0 = 147;
+ DLT_USER1 = 148;
+ DLT_USER2 = 149;
+ DLT_USER3 = 150;
+ DLT_USER4 = 151;
+ DLT_USER5 = 152;
+ DLT_USER6 = 153;
+ DLT_USER7 = 154;
+ DLT_USER8 = 155;
+ DLT_USER9 = 156;
+ DLT_USER10 = 157;
+ DLT_USER11 = 158;
+ DLT_USER12 = 159;
+ DLT_USER13 = 160;
+ DLT_USER14 = 161;
+ DLT_USER15 = 162;
+
+ //
+ // For future use with 802.11 captures - defined by AbsoluteValue
+ // Systems to store a number of bits of link-layer information
+ // including radio information:
+ //
+ // http://www.shaftnet.org/~pizza/software/capturefrm.txt
+ //
+ // but it might be used by some non-AVS drivers now or in the
+ // future.
+ //
+ DLT_IEEE802_11_RADIO_AVS = 163; // 802.11 plus AVS radio header//
+
+ //
+ // Juniper-private data link type, as per request from
+ // Hannes Gredler . The DLT_s are used
+ // for passing on chassis-internal metainformation such as
+ // QOS profiles, etc..
+ //
+ DLT_JUNIPER_MONITOR = 164;
+
+ //
+ // Reserved for BACnet MS/TP.
+ //
+ DLT_BACNET_MS_TP = 165;
+
+ //
+ // Another PPP variant as per request from Karsten Keil .
+ //
+ // This is used in some OSes to allow a kernel socket filter to distinguish
+ // between incoming and outgoing packets, on a socket intended to
+ // supply pppd with outgoing packets so it can do dial-on-demand and
+ // hangup-on-lack-of-demand; incoming packets are filtered out so they
+ // don't cause pppd to hold the connection up (you don't want random
+ // input packets such as port scans, packets from old lost connections,
+ // etc. to force the connection to stay up).
+ //
+ // The first byte of the PPP header (0xff03) is modified to accomodate
+ // the direction - 0x00 = IN, 0x01 = OUT.
+ //
+ DLT_PPP_PPPD = 166;
+
+ //
+ // Names for backwards compatibility with older versions of some PPP
+ // software; new software should use DLT_PPP_PPPD.
+ //
+ DLT_PPP_WITH_DIRECTION = DLT_PPP_PPPD;
+ DLT_LINUX_PPP_WITHDIRECTION = DLT_PPP_PPPD;
+
+ //
+ // Juniper-private data link type, as per request from
+ // Hannes Gredler . The DLT_s are used
+ // for passing on chassis-internal metainformation such as
+ // QOS profiles, cookies, etc..
+ //
+ DLT_JUNIPER_PPPOE = 167;
+ DLT_JUNIPER_PPPOE_ATM = 168;
+
+ DLT_GPRS_LLC = 169; // GPRS LLC//
+ DLT_GPF_T = 170; // GPF-T (ITU-T G.7041/Y.1303)//
+ DLT_GPF_F = 171; // GPF-F (ITU-T G.7041/Y.1303)//
+
+ //
+ // Requested by Oolan Zimmer for use in Gcom's T1/E1 line
+ // monitoring equipment.
+ //
+ DLT_GCOM_T1E1 = 172;
+ DLT_GCOM_SERIAL = 173;
+
+ //
+ // Juniper-private data link type, as per request from
+ // Hannes Gredler . The DLT_ is used
+ // for internal communication to Physical Interface Cards (PIC)
+ //
+ DLT_JUNIPER_PIC_PEER = 174;
+
+ //
+ // Link types requested by Gregor Maier of Endace
+ // Measurement Systems. They add an ERF header (see
+ // http://www.endace.com/support/EndaceRecordFormat.pdf) in front of
+ // the link-layer header.
+ //
+ DLT_ERF_ETH = 175; // Ethernet//
+ DLT_ERF_POS = 176; // Packet-over-SONET//
+
+ //
+ // Requested by Daniele Orlandi for raw LAPD
+ // for vISDN (http://www.orlandi.com/visdn/). Its link-layer header
+ // includes additional information before the LAPD header, so it's
+ // not necessarily a generic LAPD header.
+ //
+ DLT_LINUX_LAPD = 177;
+
+ //
+ // Juniper-private data link type, as per request from
+ // Hannes Gredler .
+ // The DLT_ are used for prepending meta-information
+ // like interface index, interface name
+ // before standard Ethernet, PPP, Frelay & C-HDLC Frames
+ //
+ DLT_JUNIPER_ETHER = 178;
+ DLT_JUNIPER_PPP = 179;
+ DLT_JUNIPER_FRELAY = 180;
+ DLT_JUNIPER_CHDLC = 181;
+
+ //
+ // Multi Link Frame Relay (FRF.16)
+ //
+ DLT_MFR = 182;
+
+ //
+ // Juniper-private data link type, as per request from
+ // Hannes Gredler .
+ // The DLT_ is used for internal communication with a
+ // voice Adapter Card (PIC)
+ //
+ DLT_JUNIPER_VP = 183;
+
+ //
+ // Arinc 429 frames.
+ // DLT_ requested by Gianluca Varenni .
+ // Every frame contains a 32bit A429 label.
+ // More documentation on Arinc 429 can be found at
+ // http://www.condoreng.com/support/downloads/tutorials/ARINCTutorial.pdf
+ //
+ DLT_A429 = 184;
+
+ //
+ // Arinc 653 Interpartition Communication messages.
+ // DLT_ requested by Gianluca Varenni .
+ // Please refer to the A653-1 standard for more information.
+ //
+ DLT_A653_ICM = 185;
+
+ //
+ // USB packets, beginning with a USB setup header; requested by
+ // Paolo Abeni .
+ //
+ DLT_USB = 186;
+
+ //
+ // Bluetooth HCI UART transport layer (part H:4); requested by
+ // Paolo Abeni.
+ //
+ DLT_BLUETOOTH_HCI_H4 = 187;
+
+ //
+ // IEEE 802.16 MAC Common Part Sublayer; requested by Maria Cruz
+ // .
+ //
+ DLT_IEEE802_16_MAC_CPS = 188;
+
+ //
+ // USB packets, beginning with a Linux USB header; requested by
+ // Paolo Abeni .
+ //
+ DLT_USB_LINUX = 189;
+
+ //
+ // Controller Area Network (CAN) v. 2.0B packets.
+ // DLT_ requested by Gianluca Varenni .
+ // Used to dump CAN packets coming from a CAN Vector board.
+ // More documentation on the CAN v2.0B frames can be found at
+ // http://www.can-cia.org/downloads/?269
+ //
+ DLT_CAN20B = 190;
+
+ //
+ // IEEE 802.15.4, with address fields padded, as is done by Linux
+ // drivers; requested by Juergen Schimmer.
+ //
+ DLT_IEEE802_15_4_LINUX = 191;
+
+ //
+ // Per Packet Information encapsulated packets.
+ // DLT_ requested by Gianluca Varenni .
+ //
+ DLT_PPI = 192;
+
+ //
+ // Header for 802.16 MAC Common Part Sublayer plus a radiotap radio header;
+ // requested by Charles Clancy.
+ //
+ DLT_IEEE802_16_MAC_CPS_RADIO = 193;
+
+ //
+ // Juniper-private data link type, as per request from
+ // Hannes Gredler .
+ // The DLT_ is used for internal communication with a
+ // integrated service module (ISM).
+ //
+ DLT_JUNIPER_ISM = 194;
+
+ //
+ // IEEE 802.15.4, exactly as it appears in the spec (no padding, no
+ // nothing); requested by Mikko Saarnivala .
+ //
+ DLT_IEEE802_15_4 = 195;
+
+ //
+ // Various link-layer types, with a pseudo-header, for SITA
+ // (http://www.sita.aero/); requested by Fulko Hew (fulko.hew@gmail.com).
+ //
+ DLT_SITA = 196;
+
+ //
+ // Various link-layer types, with a pseudo-header, for Endace DAG cards;
+ // encapsulates Endace ERF records. Requested by Stephen Donnelly
+ // .
+ //
+ DLT_ERF = 197;
+
+ //
+ // Special header prepended to Ethernet packets when capturing from a
+ // u10 Networks board. Requested by Phil Mulholland
+ // .
+ //
+ DLT_RAIF1 = 198;
+
+ //
+ // IPMB packet for IPMI, beginning with the I2C slave address, followed
+ // by the netFn and LUN, etc.. Requested by Chanthy Toeung
+ // .
+ //
+ DLT_IPMB = 199;
+
+ //
+ // Juniper-private data link type, as per request from
+ // Hannes Gredler .
+ // The DLT_ is used for capturing data on a secure tunnel interface.
+ //
+ DLT_JUNIPER_ST = 200;
+
+ //
+ // Bluetooth HCI UART transport layer (part H:4), with pseudo-header
+ // that includes direction information; requested by Paolo Abeni.
+ //
+ DLT_BLUETOOTH_HCI_H4_WITH_PHDR = 201;
+
+ //
+ // AX.25 packet with a 1-byte KISS header; see
+ //
+ // http://www.ax25.net/kiss.htm
+ //
+ // as per Richard Stearn .
+ //
+ DLT_AX25_KISS = 202;
+
+ //
+ // LAPD packets from an ISDN channel, starting with the address field,
+ // with no pseudo-header.
+ // Requested by Varuna De Silva .
+ //
+ DLT_LAPD = 203;
+
+ //
+ // Variants of various link-layer headers, with a one-byte direction
+ // pseudo-header prepended - zero means "received by this host",
+ // non-zero (any non-zero value) means "sent by this host" - as per
+ // Will Barker .
+ //
+ DLT_PPP_WITH_DIR = 204; // PPP - don't confuse with DLT_PPP_WITH_DIRECTION//
+ DLT_C_HDLC_WITH_DIR = 205; // Cisco HDLC//
+ DLT_FRELAY_WITH_DIR = 206; // Frame Relay//
+ DLT_LAPB_WITH_DIR = 207; // LAPB//
+
+ //
+ // 208 is reserved for an as-yet-unspecified proprietary link-layer
+ // type, as requested by Will Barker.
+ //
+
+ //
+ // IPMB with a Linux-specific pseudo-header; as requested by Alexey Neyman
+ // .
+ //
+ DLT_IPMB_LINUX = 209;
+
+ //
+ // FlexRay automotive bus - http://www.flexray.com/ - as requested
+ // by Hannes Kaelber .
+ //
+ DLT_FLEXRAY = 210;
+
+ //
+ // Media Oriented Systems Transport (MOST) bus for multimedia
+ // transport - http://www.mostcooperation.com/ - as requested
+ // by Hannes Kaelber .
+ //
+ DLT_MOST = 211;
+
+ //
+ // Local Interconnect Network (LIN) bus for vehicle networks -
+ // http://www.lin-subbus.org/ - as requested by Hannes Kaelber
+ // .
+ //
+ DLT_LIN = 212;
+
+ //
+ // X2E-private data link type used for serial line capture,
+ // as requested by Hannes Kaelber .
+ //
+ DLT_X2E_SERIAL = 213;
+
+ //
+ // X2E-private data link type used for the Xoraya data logger
+ // family, as requested by Hannes Kaelber .
+ //
+ DLT_X2E_XORAYA = 214;
+
+ //
+ // IEEE 802.15.4, exactly as it appears in the spec (no padding, no
+ // nothing), but with the PHY-level data for non-ASK PHYs (4 octets
+ // of 0 as preamble, one octet of SFD, one octet of frame length+
+ // reserved bit, and then the MAC-layer data, starting with the
+ // frame control field).
+ //
+ // Requested by Max Filippov .
+ //
+ DLT_IEEE802_15_4_NONASK_PHY = 215;
+
+ //
+ // NetBSD-specific generic "raw" link type. The class value indicates
+ // that this is the generic raw type, and the lower 16 bits are the
+ // address family we're dealing with. Those values are NetBSD-specific;
+ // do not assume that they correspond to AF_ values for your operating
+ // system.
+ //
+ DLT_CLASS_NETBSD_RAWAF = $02240000;
+
+ //
+ // The instruction encodings.
+ //
+
+ // instruction classes
+ BPF_LD = $00;
+ BPF_LDX = $01;
+ BPF_ST = $02;
+ BPF_STX = $03;
+ BPF_ALU = $04;
+ BPF_JMP = $05;
+ BPF_RET = $06;
+ BPF_MISC = $07;
+
+ // ld/ldx fields
+ BPF_W = $00;
+ BPF_H = $08;
+ BPF_B = $10;
+ BPF_IMM = $00;
+ BPF_ABS = $20;
+ BPF_IND = $40;
+ BPF_MEM = $60;
+ BPF_LEN = $80;
+ BPF_MSH = $A0;
+
+ // alu/jmp fields
+ BPF_ADD = $00;
+ BPF_SUB = $10;
+ BPF_MUL = $20;
+ BPF_DIV = $30;
+ BPF_OR = $40;
+ BPF_AND = $50;
+ BPF_LSH = $60;
+ BPF_RSH = $70;
+ BPF_NEG = $80;
+ BPF_JA = $00;
+ BPF_JEQ = $10;
+ BPF_JGT = $20;
+ BPF_JGE = $30;
+ BPF_JSET = $40;
+ BPF_K = $00;
+ BPF_X = $08;
+
+ // ret - BPF_K and BPF_X also apply
+ BPF_A = $10;
+
+ // misc
+ BPF_TAX = $00;
+ BPF_TXA = $80;
+
+ //
+ // DLT and savefile link type values are split into a class and
+ // a member of that class. A class value of 0 indicates a regular
+ // DLT_/LINKTYPE_ value.
+ //
+function DLT_CLASS(c: u_int): u_int;
+
+function DLT_NETBSD_RAWAF(af: u_int): u_int;
+function DLT_NETBSD_RAWAF_AF(c: u_int): u_int;
+function DLT_IS_NETBSD_RAWAF(c: u_int): boolean;
+
+function BPF_CLASS(code: word): word;
+function BPF_SIZE(code: word): word;
+function BPF_MODE(code: word): word;
+function BPF_OP(code: word): word;
+function BPF_SRC(code: word): word;
+function BPF_RVAL(code: word): word;
+function BPF_MISCOP(code: word): word;
+
+//
+// Macros for insn array initializers.
+//
+// #define BPF_STMT(code, k) { (u_short)(code), 0, 0, k }
+// #define BPF_JUMP(code, k, jt, jf) { (u_short)(code), jt, jf, k }
+
+implementation
+
+function BPF_WORDALIGN(x: integer): integer;
+begin
+ Result := (x + BPF_ALIGNMENT - 1) and not (BPF_ALIGNMENT - 1);
+end;
+
+function DLT_CLASS(c: u_int): u_int;
+begin
+ Result := (c and $03FF0000);
+end;
+
+function DLT_NETBSD_RAWAF(af: u_int): u_int;
+begin
+ Result := (DLT_CLASS_NETBSD_RAWAF or af);
+end;
+
+function DLT_NETBSD_RAWAF_AF(c: u_int): u_int;
+begin
+ Result := (c and $0000FFFF)
+end;
+
+function DLT_IS_NETBSD_RAWAF(c: u_int): boolean;
+begin
+ Result := (DLT_CLASS(c) = DLT_CLASS_NETBSD_RAWAF);
+end;
+
+function BPF_CLASS(code: word): word;
+begin
+ Result := (code and $07);
+end;
+
+function BPF_SIZE(code: word): word;
+begin
+ Result := (code and $18);
+end;
+
+function BPF_MODE(code: word): word;
+begin
+ Result := (code and $E0);
+
+end;
+
+function BPF_OP(code: word): word;
+begin
+ Result := (code and $F0);
+
+end;
+
+function BPF_SRC(code: word): word;
+begin
+ Result := (code and $08);
+
+end;
+
+function BPF_RVAL(code: word): word;
+begin
+ Result := (code and $18);
+
+end;
+
+function BPF_MISCOP(code: word): word;
+begin
+ Result := (code and $F8);
+
+end;
+
+end.
diff --git a/EvilWorks.Api.WinPCap.pas b/EvilWorks.Api.WinPCap.pas
new file mode 100644
index 0000000..ff8d915
--- /dev/null
+++ b/EvilWorks.Api.WinPCap.pas
@@ -0,0 +1,372 @@
+unit EvilWorks.Api.WinPCap;
+
+// Translated from v1.4.2.11
+
+interface
+
+uses
+ WinApi.Windows,
+ EvilWorks.Api.Winsock2, // you can remove this and use WinApi.Winsock instead. Required for u_int, etc
+ EvilWorks.Api.WinPCap.Bpf;
+
+const
+ SWinPcap = 'wpcap.dll';
+
+ PCAP_SRC_IF_STRING = 'rpcap://';
+
+ PCAP_VERSION_MAJOR = 2;
+ PCAP_VERSION_MINOR = 4;
+
+ PCAP_ERRBUF_SIZE = 256;
+ PCAP_IF_LOOPBACK = $00000001; // interface is loopback
+
+ //
+ // Error codes for the pcap API.
+ // These will all be negative, so you can check for the success or
+ // failure of a call that returns these codes by checking for a
+ // negative value.
+ //
+
+ PCAP_ERROR = - 1; // generic error code
+ PCAP_ERROR_BREAK = - 2; // loop terminated by pcap_breakloop
+ PCAP_ERROR_NOT_ACTIVATED = - 3; // the capture needs to be activated
+ PCAP_ERROR_ACTIVATED = - 4; // the operation can't be performed on already activated captures
+ PCAP_ERROR_NO_SUCH_DEVICE = - 5; // no such device exists
+ PCAP_ERROR_RFMON_NOTSUP = - 6; // this device doesn't support rfmon (monitor) mode
+ PCAP_ERROR_NOT_RFMON = - 7; // operation supported only in monitor mode
+ PCAP_ERROR_PERM_DENIED = - 8; // no permission to open the device
+ PCAP_ERROR_IFACE_NOT_UP = - 9; // interface isn't up
+
+ //
+ // Warning codes for the pcap API.
+ // These will all be positive and non-zero, so they won't look like
+ // errors.
+ //
+
+ PCAP_WARNING = 1; // generic warning code */
+ PCAP_WARNING_PROMISC_NOTSUP = 2; // this device doesn't support promiscuous mode */
+
+ MODE_CAPT = 0;
+ MODE_STAT = 1;
+ MODE_MON = 2;
+
+ PCAP_OPENFLAG_PROMISCUOUS = 1;
+
+type
+ // extra data types.
+ pu_char = ^u_char;
+ ppu_char = ^pu_char;
+
+ ppinteger = ^pinteger;
+
+ // pcap_t = pcap;
+ Pcap = pointer;
+ ppcap = ^Pcap;
+ pcap_t = Pcap;
+ ppcap_t = ^pcap_t;
+
+ // pcap_dumper_t = pcap_dumper;
+ pcap_dumper = pointer;
+ ppcap_dumper = ^pcap_dumper;
+
+ pcap_dumper_t = pcap_dumper;
+ ppcap_dumper_t = ^pcap_dumper_t;
+
+ // pcap_if_t = pcap_if;
+ // pcap_addr_t = pcap_addr;
+
+ // The first record in the file contains saved values for some
+ // of the flags used in the printout phases of tcpdump.
+ // Many fields here are 32 bit ints so compilers won't insert unwanted
+ // padding; these files need to be interchangeable across architectures.
+ //
+ // Do not change the layout of this structure, in any way (this includes
+ // changes that only affect the length of fields in this structure).
+ //
+ // Also, do not change the interpretation of any of the members of this
+ // structure, in any way (this includes using values other than
+ // LINKTYPE_ values, as defined in "savefile.c", in the "linktype"
+ // field).
+ //
+ // Instead:
+ //
+ // introduce a new structure for the new format, if the layout
+ // of the structure changed;
+ //
+ // send mail to "tcpdump-workers@lists.tcpdump.org", requesting
+ // a new magic number for your new capture file format, and, when
+ // you get the new magic number, put it in "savefile.c";
+ //
+ // use that magic number for save files with the changed file
+ // header;
+ //
+ // make the code in "savefile.c" capable of reading files with
+ // the old file header as well as files with the new file header
+ // (using the magic number to determine the header format).
+ //
+ // Then supply the changes as a patch at
+ //
+ // http://sourceforge.net/projects/libpcap/
+ //
+ // so that future versions of libpcap and programs that use it (such as
+ // tcpdump) will be able to read your new capture file format.
+
+ { pcap_file_header }
+ pcap_file_header = record
+ magic: bpf_u_int32;
+ version_major: u_short;
+ version_minor: u_short;
+ thiszone: bpf_int32; // gmt to local correction
+ sigfigs: bpf_u_int32; // accuracy of timestamps
+ snaplen: bpf_u_int32; // max length saved portion of each pkt
+ linktype: bpf_u_int32; // data link type (LINKTYPE_*)
+ end;
+
+ { pcap_direction_t }
+ pcap_direction_t = (
+ PCAP_D_INOUT = 0,
+ PCAP_D_IN,
+ PCAP_D_OUT
+ );
+
+ //
+ // Generic per-packet information, as supplied by libpcap.
+ //
+ // The time stamp can and should be a "struct timeval", regardless of
+ // whether your system supports 32-bit tv_sec in "struct timeval",
+ // 64-bit tv_sec in "struct timeval", or both if it supports both 32-bit
+ // and 64-bit applications. The on-disk format of savefiles uses 32-bit
+ // tv_sec (and tv_usec); this structure is irrelevant to that. 32-bit
+ // and 64-bit versions of libpcap, even if they're on the same platform,
+ // should supply the appropriate version of "struct timeval", even if
+ // that's not what the underlying packet capture mechanism supplies.
+ //
+
+ { pcap_pkthdr }
+ ppcap_pkthdr = ^pcap_pkthdr;
+ pppcap_pkthdr = ^ppcap_pkthdr;
+
+ pcap_pkthdr = record
+ ts: timeval; // time stamp */
+ caplen: bpf_u_int32; // length of portion present */
+ len: bpf_u_int32; // length this packet (off wire) */
+ end;
+
+ //
+ // As returned by the pcap_stats()
+ //
+
+ { pcap_stat }
+ ppcap_stat = ^pcap_stat;
+
+ pcap_stat = record
+ ps_recv: u_int; // number of packets received
+ ps_drop: u_int; // number of packets dropped
+ ps_ifdrop: u_int; // drops by interface XXX not yet supported
+ { #ifdef HAVE_REMOTE }
+ ps_capt: u_int; // number of packets that are received by the application; please get rid off the Win32 ifdef
+ ps_sent: u_int; // number of packets sent by the server on the network
+ ps_netdrop: u_int; // number of packets lost on the network
+ { #endif HAVE_REMOTE }
+ end;
+
+ //
+ // As returned by the pcap_stats_ex()
+ //
+
+ { pcap_stat_ex }
+ ppcap_stat_ex = ^pcap_stat_ex;
+
+ pcap_stat_ex = record
+ rx_packets: u_long; // total packets received
+ tx_packets: u_long; // total packets transmitted
+ rx_bytes: u_long; // total bytes received
+ tx_bytes: u_long; // total bytes transmitted
+ rx_errors: u_long; // bad packets received
+ tx_errors: u_long; // packet transmit problems
+ rx_dropped: u_long; // no space in Rx buffers
+ tx_dropped: u_long; // no space available for Tx
+ multicast: u_long; // multicast packets received
+ collisions: u_long;
+
+ // detailed rx_errors
+ rx_length_errors: u_long;
+ rx_over_errors: u_long; // receiver ring buff overflow
+ rx_crc_errors: u_long; // recv'd pkt with crc error
+ rx_frame_errors: u_long; // recv'd frame alignment error
+ rx_fifo_errors: u_long; // recv'r fifo overrun
+ rx_missed_errors: u_long; // recv'r missed packet
+
+ // detailed tx_errors
+ tx_aborted_errors: u_long;
+ tx_carrier_errors: u_long;
+ tx_fifo_errors: u_long;
+ tx_heartbeat_errors: u_long;
+ tx_window_errors: u_long;
+ end;
+
+ { pcap_addr }
+ ppcap_addr = ^pcap_addr;
+
+ pcap_addr = record
+ next: ppcap_addr;
+ addr: psockaddr; // address
+ netmask: psockaddr; // netmask for that address
+ broadaddr: psockaddr; // broadcast address for that address
+ dstaddr: psockaddr; // P2P destination address for that address
+ end;
+
+ pcap_addr_t = ppcap_addr;
+ ppcap_addr_t = ^pcap_addr_t;
+
+ ppcap_handler = ^pcap_handler;
+ pcap_handler = procedure(c: pu_char; h: ppcap_pkthdr; r: pu_char);
+
+ //
+ // Item in a list of interfaces.
+ //
+
+ { pcap_if }
+ ppcap_if = ^pcap_if;
+ pppcap_if_t = ^ppcap_if_t;
+
+ pcap_if = record
+ next: ppcap_if;
+ name: pansichar; // name to hand to "pcap_open_live()
+ description: pansichar; // textual description of interface, or NULL
+ addresses: ppcap_addr;
+ flags: bpf_u_int32; // PCAP_IF_ interface flags
+ end;
+
+ pcap_if_t = pcap_if;
+ ppcap_if_t = ^pcap_if_t;
+
+ { pcap_rmtauth }
+ ppcap_rmtauth = ^pcap_rmtauth;
+
+ pcap_rmtauth = record
+ typ: integer;
+ username: pansichar;
+ password: pansichar;
+ end;
+
+function pcap_lookupdev(errbuff: pansichar): pansichar; cdecl; external SWinPcap name 'pcap_lookupdev';
+function pcap_lookupnet(const device: pansichar; netp: bpf_u_int32; maskp: bpf_u_int32; errbuf: pansichar): integer; cdecl; external SWinPcap name 'pcap_lookupnet';
+
+function pcap_create(const a: pansichar; b: pansichar): ppcap_t; cdecl; external SWinPcap name 'pcap_create';
+function pcap_set_snaplen(p: ppcap_t; v: integer): integer; cdecl; external SWinPcap name 'pcap_set_snaplen';
+function pcap_set_promisc(p: ppcap_t; v: integer): integer; cdecl; external SWinPcap name 'pcap_set_promisc';
+function pcap_can_set_rfmon(p: ppcap_t): integer; cdecl; external SWinPcap name 'pcap_can_set_rfmon';
+function pcap_set_rfmon(p: ppcap_t; v: integer): integer; cdecl; external SWinPcap name 'pcap_set_rfmon';
+function pcap_set_timeout(p: ppcap_t; v: integer): integer; cdecl; external SWinPcap name 'pcap_set_timeout';
+function pcap_set_buffer_size(p: ppcap_t; v: integer): integer; cdecl; external SWinPcap name 'pcap_set_buffer_size';
+function pcap_activate(p: ppcap_t): integer; cdecl; external SWinPcap name 'pcap_activate';
+
+function pcap_open_live(const device: pansichar; snaplen, promisc, to_ms: integer; ebuf: pansichar): ppcap_t; cdecl; external SWinPcap name 'pcap_open_live';
+function pcap_open_dead(linktype, snaplen: integer): ppcap_t; cdecl; external SWinPcap name 'pcap_open_dead';
+function pcap_open_offline(const fname: pansichar; errbuf: pansichar): ppcap_t; cdecl; external SWinPcap name 'pcap_open_offline';
+function pcap_hopen_offline(p: intptr; c: pansichar): ppcap_t; cdecl; external SWinPcap name 'pcap_hopen_offline';
+
+procedure pcap_close(p: ppcap_t); cdecl; external SWinPcap name 'pcap_close';
+function pcap_loop(p: ppcap_t; cnt: integer; callback: pcap_handler; user: pu_char): integer; cdecl; external SWinPcap name 'pcap_loop';
+function pcap_dispatch(p: ppcap_t; cnt: integer; callback: pcap_handler; user: pu_char): integer; cdecl; external SWinPcap name 'pcap_dispatch';
+function pcap_next(p: ppcap_t; pkt_header: ppcap_pkthdr): pu_char; cdecl; external SWinPcap name 'pcap_next';
+
+function pcap_next_ex(p: ppcap_t; pkt_header: pppcap_pkthdr; const pkt_data: ppu_char): integer; cdecl; external SWinPcap name 'pcap_next_ex';
+procedure pcap_breakloop(p: ppcap_t); cdecl; external SWinPcap name 'pcap_breakloop';
+function pcap_stats(p: ppcap_t; ps: ppcap_stat): integer; cdecl; external SWinPcap name 'pcap_stats';
+function pcap_setfilter(p: ppcap_t; prg: pbpf_program): integer; cdecl; external SWinPcap name 'pcap_setfilter';
+function pcap_setdirection(p: ppcap_t; dir: pcap_direction_t): integer; cdecl; external SWinPcap name 'pcap_setdirection';
+
+function pcap_getnonblock(p: ppcap_t; errbuf: pansichar): integer; cdecl; external SWinPcap name 'pcap_getnonblock';
+function pcap_setnonblock(p: ppcap_t; nonblock: integer; errbuf: pansichar): integer; cdecl; external SWinPcap name 'pcap_setnonblock';
+function pcap_inject(p: ppcap_t; const data: pointer; size: size_t): integer; cdecl; external SWinPcap name 'pcap_inject';
+function pcap_sendpacket(p: ppcap_t; const buf: pu_char; size: integer): integer; cdecl; external SWinPcap name 'pcap_sendpacket';
+
+function pcap_statustostr(code: integer): pansichar; cdecl; external SWinPcap name 'pcap_statustostr';
+function pcap_strerror(code: integer): pansichar; cdecl; external SWinPcap name 'pcap_strerror';
+function pcap_geterr(p: ppcap_t): pansichar; cdecl; external SWinPcap name 'pcap_geterr';
+procedure pcap_perror(p: ppcap_t; buff: pansichar); cdecl; external SWinPcap name 'pcap_perror';
+
+function pcap_compile(p: ppcap_t; fp: pbpf_program; const str: pansichar; optimize: integer; netmask: bpf_u_int32): integer; cdecl; external SWinPcap name 'pcap_compile';
+function pcap_compile_nopcap(snaplen_arg, linktype_arg: integer; progrm: pbpf_program; const buf: pansichar; optimize: integer; mask: bpf_u_int32): integer; cdecl;
+ external SWinPcap name 'pcap_compile_nopcap';
+procedure pcap_freecode(prg: pbpf_program); cdecl; external SWinPcap name 'pcap_freecode';
+
+function pcap_offline_filter(fp: pbpf_program; const pkt_hdr: ppcap_pkthdr; const pkt_data: pu_char): integer; cdecl; external SWinPcap name 'pcap_offline_filter';
+
+function pcap_datalink(p: ppcap): integer; cdecl; external SWinPcap name 'pcap_datalink';
+function pcap_datalink_ext(p: ppcap): integer; cdecl; external SWinPcap name 'pcap_datalink_ext';
+function pcap_list_datalinks(p: ppcap; i: ppinteger): integer; cdecl; external SWinPcap name 'pcap_list_datalinks';
+function pcap_set_datalink(p: ppcap; i: integer): integer; cdecl; external SWinPcap name 'pcap_set_datalink';
+function pcap_datalink_name_to_val(const name: pansichar): integer; cdecl; external SWinPcap name 'pcap_datalink_name_to_val';
+function pcap_datalink_val_to_name(i: integer): pansichar; cdecl; external SWinPcap name 'pcap_datalink_val_to_name';
+function pcap_datalink_val_to_description(i: integer): pansichar; cdecl; external SWinPcap name 'pcap_datalink_val_to_description';
+procedure pcap_free_datalinks(i: integer); cdecl; external SWinPcap name 'pcap_free_datalinks';
+
+function pcap_snapshot(p: ppcap): integer; cdecl; external SWinPcap name 'pcap_snapshot';
+function pcap_is_swapped(p: ppcap): integer; cdecl; external SWinPcap name 'pcap_is_swapped';
+function pcap_major_version(p: ppcap): integer; cdecl; external SWinPcap name 'pcap_major_version';
+function pcap_minor_version(p: ppcap): integer; cdecl; external SWinPcap name 'pcap_minor_version';
+
+// XXX
+function pcap_file(p: ppcap): PHandle; cdecl; external SWinPcap name 'pcap_file';
+function pcap_fileno(p: ppcap): integer; cdecl; external SWinPcap name 'pcap_fileno';
+
+function pcap_dump_open(p: ppcap_t; const data: pansichar): pcap_dumper_t; cdecl; external SWinPcap name 'pcap_dump_open';
+function pcap_dump_fopen(p: ppcap_t; fp: PHandle): pcap_dumper_t; cdecl; external SWinPcap name 'pcap_dump_fopen';
+function pcap_dump_file(dmp: ppcap_dumper_t): PHandle; cdecl; external SWinPcap name 'pcap_dump_file';
+function pcap_dump_ftell(dmp: ppcap_dumper_t): long; cdecl; external SWinPcap name 'pcap_dump_ftell';
+function pcap_dump_flush(dmp: ppcap_dumper_t): integer; cdecl; external SWinPcap name 'pcap_dump_flush';
+procedure pcap_dump_close(dmp: ppcap_dumper_t); cdecl; external SWinPcap name 'pcap_dump_close';
+procedure pcap_dump(p: pu_char; const h: ppcap_pkthdr; const sp: pu_char); cdecl; external SWinPcap name 'pcap_dump';
+
+function pcap_findalldevs(devs: pppcap_if_t; errbuf: pansichar): integer; cdecl; external SWinPcap name 'pcap_findalldevs';
+function pcap_findalldevs_ex(source: pansichar; auth: ppcap_rmtauth; alldevs: pppcap_if_t; errbuff: pansichar): integer; cdecl; external SWinPcap name 'pcap_findalldevs_ex';
+procedure pcap_freealldevs(devs: ppcap_if_t); cdecl; external SWinPcap name 'pcap_freealldevs';
+
+function pcap_lib_version: pansichar; cdecl; external SWinPcap name 'pcap_lib_version';
+
+// XXX this guy lives in the Bpf tree
+function bpf_filter(const struct: pbpf_insn; const flt: pu_char; a, b: u_int): u_int; cdecl; external SWinPcap name 'bpf_filter';
+function bpf_validate(const struct: pbpf_insn; i: integer): integer; cdecl; external SWinPcap name 'bpf_validate';
+function bpf_image(const struct: pbpf_insn; a: integer): pansichar; cdecl; external SWinPcap name 'bpf_image';
+procedure bpf_dump(const struct: pbpf_program; a: integer); cdecl; external SWinPcap name 'bpf_dump';
+
+//
+// Win32 definitions
+//
+function pcap_setbuff(p: ppcap_t; dim: integer): integer; cdecl; external SWinPcap name 'pcap_setbuff';
+function pcap_setmode(p: ppcap_t; mode: integer): integer; cdecl; external SWinPcap name 'pcap_setmode';
+function pcap_setmintocopy(p: ppcap_t; size: integer): integer; cdecl; external SWinPcap name 'pcap_setmintocopy';
+
+function pcap_open(const source: pansichar; snaplen, flags, read_timeout: integer; auth: ppcap_rmtauth; errbuf: pansichar): ppcap_t; cdecl; external SWinPcap name 'pcap_open';
+
+//
+// Macros for the value returned by pcap_datalink_ext().
+//
+// If LT_FCS_LENGTH_PRESENT(x) is true, the LT_FCS_LENGTH(x) macro
+// gives the FCS length of packets in the capture.
+//
+function LT_FCS_LENGTH_PRESENT(x: u_int): u_int;
+function LT_FCS_LENGTH(x: u_int): u_int;
+function LT_FCS_DATALINK_EXT(x: u_int): u_int;
+
+implementation
+
+function LT_FCS_LENGTH_PRESENT(x: u_int): u_int;
+begin
+ Result := (x and $04000000);
+end;
+
+function LT_FCS_LENGTH(x: u_int): u_int;
+begin
+ Result := ((x and $F0000000) shr 28);
+end;
+
+function LT_FCS_DATALINK_EXT(x: u_int): u_int;
+begin
+ Result := (((x and $F) shl 28) or $04000000);
+end;
+
+end.
diff --git a/EvilWorks.Api.ZLib.pas b/EvilWorks.Api.ZLib.pas
new file mode 100644
index 0000000..1a317ba
--- /dev/null
+++ b/EvilWorks.Api.ZLib.pas
@@ -0,0 +1,327 @@
+//
+// EvilLibrary by Vedran Vuk 2010-2012
+//
+// Name: EvilWorks.Api.ZLib
+// Description: ZLib header. Taken from ZLibExApi.pas 1.2.7 by Brent Sherwood.
+// File last change date: October 20th. 2012
+// File version: Dev 0.0.0
+// Licence: See below.
+//
+// Original author Brent Sherwood - http://www.base2ti.com
+// Original file ZLibExApi.pas 1.2.7
+// Original copyright copyright (c) 2000-2012 base2 technologies
+// copyright (c) 1995-2002 Borland Software Corporation
+//
+
+unit EvilWorks.Api.ZLib;
+
+interface
+
+const
+
+ //
+ // Version IDs
+ //
+
+ ZLIB_VERSION: PAnsiChar = '1.2.7';
+
+ ZLIB_VERNUM = $1270;
+
+ ZLIB_VER_MAJOR = 1;
+ ZLIB_VER_MINOR = 2;
+ ZLIB_VER_REVISION = 7;
+ ZLIB_VER_SUBREVISION = 0;
+
+ //
+ // Compression methods
+ //
+
+ Z_DEFLATED = 8;
+
+ //
+ // Information flags
+ //
+
+ Z_INFO_FLAG_SIZE = $1;
+ Z_INFO_FLAG_CRC = $2;
+ Z_INFO_FLAG_ADLER = $4;
+
+ Z_INFO_NONE = 0;
+ Z_INFO_DEFAULT = Z_INFO_FLAG_SIZE or Z_INFO_FLAG_CRC;
+
+ //
+ // Flush constants
+ //
+
+ Z_NO_FLUSH = 0;
+ Z_PARTIAL_FLUSH = 1;
+ Z_SYNC_FLUSH = 2;
+ Z_FULL_FLUSH = 3;
+ Z_FINISH = 4;
+ Z_BLOCK = 5;
+ Z_TREES = 6;
+
+ //
+ // Return codes
+ //
+
+ Z_OK = 0;
+ Z_STREAM_END = 1;
+ Z_NEED_DICT = 2;
+ Z_ERRNO = ( - 1);
+ Z_STREAM_ERROR = ( - 2);
+ Z_DATA_ERROR = ( - 3);
+ Z_MEM_ERROR = ( - 4);
+ Z_BUF_ERROR = ( - 5);
+ Z_VERSION_ERROR = ( - 6);
+
+ //
+ // Compression levels
+ //
+
+ Z_NO_COMPRESSION = 0;
+ Z_BEST_SPEED = 1;
+ Z_BEST_COMPRESSION = 9;
+ Z_DEFAULT_COMPRESSION = ( - 1);
+
+ //
+ // Compression strategies
+ //
+
+ Z_FILTERED = 1;
+ Z_HUFFMAN_ONLY = 2;
+ Z_RLE = 3;
+ Z_FIXED = 4;
+ Z_DEFAULT_STRATEGY = 0;
+
+ //
+ // Data types
+ //
+
+ Z_BINARY = 0;
+ Z_ASCII = 1;
+ Z_TEXT = Z_ASCII;
+ Z_UNKNOWN = 2;
+
+ //
+ // Return code messages
+ //
+
+ z_errmsg: array [0 .. 9] of string = (
+ 'Need dictionary', // Z_NEED_DICT (2)
+ 'Stream end', // Z_STREAM_END (1)
+ 'OK', // Z_OK (0)
+ 'File error', // Z_ERRNO (-1)
+ 'Stream error', // Z_STREAM_ERROR (-2)
+ 'Data error', // Z_DATA_ERROR (-3)
+ 'Insufficient memory', // Z_MEM_ERROR (-4)
+ 'Buffer error', // Z_BUF_ERROR (-5)
+ 'Incompatible version', // Z_VERSION_ERROR (-6)
+ ''
+ );
+
+type
+ TZAlloc = function(opaque: Pointer; items, size: Integer): Pointer; cdecl;
+ TZFree = procedure(opaque, block: Pointer); cdecl;
+
+ //
+ // TZStreamRec
+ //
+
+ TZStreamRec = packed record
+ next_in: PByte; // next input byte
+ avail_in: Cardinal; // number of bytes available at next_in
+ total_in: Longword; // total nb of input bytes read so far
+
+ next_out: PByte; // next output byte should be put here
+ avail_out: Cardinal; // remaining free space at next_out
+ total_out: Longword; // total nb of bytes output so far
+
+ msg: PAnsiChar; // last error message, NULL if no error
+ state: Pointer; // not visible by applications
+
+ zalloc: TZAlloc; // used to allocate the internal state
+ zfree: TZFree; // used to free the internal state
+ opaque: Pointer; // private data object passed to zalloc and zfree
+
+ data_type: Integer; // best guess about the data type: ascii or binary
+ adler: Longword; // adler32 value of the uncompressed data
+ reserved: Longword; // reserved for future use
+ end;
+
+{ Macros }
+function deflateInit(var strm: TZStreamRec; level: Integer): Integer; inline;
+function deflateInit2(var strm: TZStreamRec; level, method, windowBits, memLevel, strategy: Integer): Integer; inline;
+function inflateInit(var strm: TZStreamRec): Integer; inline;
+function inflateInit2(var strm: TZStreamRec; windowBits: Integer): Integer; inline;
+
+{ External routines }
+function deflateInit_(var strm: TZStreamRec; level: Integer; version: PAnsiChar; recsize: Integer): Integer;
+function deflateInit2_(var strm: TZStreamRec; level, method, windowBits, memLevel, strategy: Integer; version: PAnsiChar; recsize: Integer): Integer;
+function deflate(var strm: TZStreamRec; flush: Integer): Integer;
+function deflateEnd(var strm: TZStreamRec): Integer;
+function deflateReset(var strm: TZStreamRec): Integer;
+function inflateInit_(var strm: TZStreamRec; version: PAnsiChar; recsize: Integer): Integer;
+function inflateInit2_(var strm: TZStreamRec; windowBits: Integer; version: PAnsiChar; recsize: Integer): Integer;
+function inflate(var strm: TZStreamRec; flush: Integer): Integer;
+function inflateEnd(var strm: TZStreamRec): Integer;
+function inflateReset(var strm: TZStreamRec): Integer;
+function adler32(adler: Longint; const buf; len: Integer): Longint;
+function crc32(crc: Longint; const buf; len: Integer): Longint;
+
+{ Utilities }
+function ZResultToString(const aResult: integer): string;
+
+implementation
+
+function ZResultToString(const aResult: integer): string;
+begin
+ case aResult of
+ Z_OK:
+ Result := 'Z_OK';
+ Z_STREAM_END:
+ Result := 'Z_STREAM_END';
+ Z_NEED_DICT:
+ Result := 'Z_NEED_DICT';
+ Z_ERRNO:
+ Result := 'Z_ERRNO';
+ Z_STREAM_ERROR:
+ Result := 'Z_STREAM_ERROR';
+ Z_DATA_ERROR:
+ Result := 'Z_DATA_ERROR';
+ Z_MEM_ERROR:
+ Result := 'Z_MEM_ERROR';
+ Z_BUF_ERROR:
+ Result := 'Z_BUF_ERROR';
+ Z_VERSION_ERROR:
+ Result := 'Z_VERSION_ERROR';
+ else
+ Result := 'Unknown return value.';
+ end;
+end;
+
+{*************************************************************************************************
+* link zlib code *
+* *
+* bcc32 flags *
+* -c -O2 -Ve -X -pr -a8 -b -d -k- -vi -tWM -u- *
+* *
+* note: do not reorder the following -- doing so will result in external *
+* functions being undefined *
+*************************************************************************************************}
+
+{$IFDEF WIN64}
+{$L ..\Lib\ZLib\win64\deflate.obj}
+{$L ..\Lib\ZLib\win64\inflate.obj}
+{$L ..\Lib\ZLib\win64\inftrees.obj}
+{$L ..\Lib\ZLib\win64\infback.obj}
+{$L ..\Lib\ZLib\win64\inffast.obj}
+{$L ..\Lib\ZLib\win64\trees.obj}
+{$L ..\Lib\ZLib\win64\compress.obj}
+{$L ..\Lib\ZLib\win64\adler32.obj}
+{$L ..\Lib\ZLib\win64\crc32.obj}
+{$ELSE}
+{$L ..\Lib\ZLib\win32\deflate.obj}
+{$L ..\Lib\ZLib\win32\inflate.obj}
+{$L ..\Lib\ZLib\win32\inftrees.obj}
+{$L ..\Lib\ZLib\win32\infback.obj}
+{$L ..\Lib\ZLib\win32\inffast.obj}
+{$L ..\Lib\ZLib\win32\trees.obj}
+{$L ..\Lib\ZLib\win32\compress.obj}
+{$L ..\Lib\ZLib\win32\adler32.obj}
+{$L ..\Lib\ZLib\win32\crc32.obj}
+{$ENDIF}
+
+{ ====== }
+{ Macros }
+{ ====== }
+
+function deflateInit(var strm: TZStreamRec; level: Integer): Integer;
+begin
+ result := deflateInit_(strm, level, ZLIB_VERSION, SizeOf(TZStreamRec));
+end;
+
+function deflateInit2(var strm: TZStreamRec; level, method, windowBits, memLevel, strategy: Integer): Integer;
+begin
+ result := deflateInit2_(strm, level, method, windowBits, memLevel, strategy, ZLIB_VERSION, SizeOf(TZStreamRec));
+end;
+
+function inflateInit(var strm: TZStreamRec): Integer;
+begin
+ result := inflateInit_(strm, ZLIB_VERSION, SizeOf(TZStreamRec));
+end;
+
+function inflateInit2(var strm: TZStreamRec; windowBits: Integer): Integer;
+begin
+ result := inflateInit2_(strm, windowBits, ZLIB_VERSION, SizeOf(TZStreamRec));
+end;
+
+{ ================= }
+{ External routines }
+{ ================= }
+
+function deflateInit_(var strm: TZStreamRec; level: Integer; version: PAnsiChar; recsize: Integer): Integer; external;
+
+function deflateInit2_(var strm: TZStreamRec; level, method, windowBits, memLevel, strategy: Integer; version: PAnsiChar; recsize: Integer): Integer; external;
+
+function deflate(var strm: TZStreamRec; flush: Integer): Integer; external;
+
+function deflateEnd(var strm: TZStreamRec): Integer; external;
+
+function deflateReset(var strm: TZStreamRec): Integer; external;
+
+function inflateInit_(var strm: TZStreamRec; version: PAnsiChar; recsize: Integer): Integer; external;
+
+function inflateInit2_(var strm: TZStreamRec; windowBits: Integer; version: PAnsiChar; recsize: Integer): Integer; external;
+
+function inflate(var strm: TZStreamRec; flush: Integer): Integer; external;
+
+function inflateEnd(var strm: TZStreamRec): Integer; external;
+
+function inflateReset(var strm: TZStreamRec): Integer; external;
+
+function adler32(adler: Longint; const buf; len: Integer): Longint; external;
+
+function crc32(crc: Longint; const buf; len: Integer): Longint; external;
+
+{ ============================= }
+{ ZLib function implementations }
+{ ============================= }
+
+function zcalloc(opaque: Pointer; items, size: Integer): Pointer;
+begin
+ GetMem(result, items * size);
+end;
+
+procedure zcfree(opaque, block: Pointer);
+begin
+ FreeMem(block);
+end;
+
+{ ========================== }
+{ C function implementations }
+{ ========================== }
+
+function memset(p: Pointer; b: Byte; count: Integer): Pointer; cdecl;
+begin
+ FillChar(p^, count, b);
+
+ result := p;
+end;
+
+procedure memcpy(dest, source: Pointer; count: Integer); cdecl;
+begin
+ Move(source^, dest^, count);
+end;
+
+{$IFNDEF WIN64}
+
+
+procedure _llmod;
+asm
+ jmp System.@_llmod;
+end;
+
+{$ENDIF}
+
+end.
diff --git a/EvilWorks.Crypto.HMAC_SHA1.pas b/EvilWorks.Crypto.HMAC_SHA1.pas
new file mode 100644
index 0000000..59e72c9
--- /dev/null
+++ b/EvilWorks.Crypto.HMAC_SHA1.pas
@@ -0,0 +1,4018 @@
+(*============================================================================================================
+
+ EvilLibrary by Vedran Vuk 2010-2012
+
+ Name: EvilWorks.Crypto.HMAC_SHA1
+ Description: HMAC_SHA1 hasher. Taken from "Fundamentals 4.00" chash.pas library version 4.15.
+ Original Copyright: Copyright © 1999-2011, David J Butler
+ Original Home page: http://fundementals.sourceforge.net
+ Original Forum: http://sourceforge.net/forum/forum.php?forum_id=2117
+ Original E-mail: fundamentalslib at gmail.com
+ File last change date: August 15th. 2012
+ File version: 0.0.1
+ Licence: Free as in beer.
+
+ ===========================================================================================================*)
+
+unit EvilWorks.Crypto.HMAC_SHA1;
+
+{$EXTENDEDSYNTAX ON}
+{$IOCHECKS ON}
+{$LONGSTRINGS ON}
+{$BOOLEVAL OFF}
+{$WRITEABLECONST OFF}
+{$MINENUMSIZE 1}
+{$OPTIMIZATION ON}
+{$INLINE ON}
+{$HIGHCHARUNICODE OFF}
+
+{ }
+{ Windows platform }
+{ }
+{$IFDEF DOT_NET}
+{$DEFINE WindowsPlatform}
+{$ENDIF}
+{$IFDEF OS_WIN32}
+{$DEFINE WindowsPlatform}
+{$ENDIF}
+{$IFDEF OS_WIN64}
+{$DEFINE WindowsPlatform}
+{$ENDIF}
+
+{ }
+{ CPU type }
+{ }
+{$IFNDEF ManagedCode}
+{$DEFINE NativeCode}
+{$ENDIF}
+{$IFDEF CPU386}
+{$DEFINE INTEL386}
+{$DEFINE CPU_INTEL386}
+{$ENDIF}
+{$IFDEF CPUX64}
+{$DEFINE CPU_X86_64}
+{$ENDIF}
+{$IFDEF CPU86_64}
+{$DEFINE CPU_X86_64}
+{$ENDIF}
+{$IFDEF CPU68K}
+{$DEFINE CPU_68K}
+{$ENDIF}
+{$IFDEF CPUPPC}
+{$DEFINE CPU_POWERPC}
+{$ENDIF}
+{$IFDEF CPUPPC64}
+{$DEFINE CPU_POWERPC64}
+{$ENDIF}
+{$IFDEF CPUARM}
+{$DEFINE CPU_ARM}
+{$ENDIF}
+
+{ }
+{ Assembler style }
+{ }
+{$IFNDEF PurePascal}
+{$IFNDEF ManagedCode}
+{$IFDEF CPU_X86_64}
+{$DEFINE ASMX86_64}
+{$ENDIF}
+{$IFDEF CPU_INTEL386}
+{$DEFINE ASM386}
+{$IFDEF DELPHI}{$IFDEF OS_WIN32}
+{$DEFINE ASM386_DELPHI}
+{$IFNDEF UseInline} {$DEFINE ASM386_DELPHI_INLINE_OFF} {$ENDIF}
+{$ENDIF}{$ENDIF}
+{$IFDEF FREEPASCAL2_UP}
+{$DEFINE ASM386_FREEPASCAL}
+{$ENDIF}
+{$ENDIF}
+{$ENDIF}
+{$ENDIF}
+
+{ }
+{ Function inlining }
+{ }
+{$IFDEF SupportInline}
+{$IFNDEF SupportInlineIsBuggy}
+{$IFNDEF PurePascal}
+{$DEFINE UseInline}
+{$ENDIF}
+{$ENDIF}
+{$ENDIF}
+
+{ }
+{ Standard compiler directives }
+{ }
+{$EXTENDEDSYNTAX ON}
+{$IOCHECKS ON}
+{$LONGSTRINGS ON}
+{$BOOLEVAL OFF}
+{$WRITEABLECONST OFF}
+{$MINENUMSIZE 1}
+{$IFDEF DEBUG}
+{$ASSERTIONS ON}
+{$DEBUGINFO ON}
+{$OVERFLOWCHECKS ON}
+{$RANGECHECKS ON}
+{$WARNINGS ON}
+{$HINTS ON}
+{$ELSE}
+{$ASSERTIONS OFF}
+{$DEBUGINFO OFF}
+{$OVERFLOWCHECKS OFF}
+{$RANGECHECKS OFF}
+{$WARNINGS OFF}
+{$HINTS OFF}
+{$ENDIF}
+{$IFDEF CLR}
+{$UNSAFECODE OFF}
+{$ENDIF}
+{$IFDEF DELPHI}
+{$OPTIMIZATION ON}
+{$ENDIF}
+{$IFDEF DELPHI2005_UP}
+{$INLINE ON}
+{$ENDIF}
+{$IFDEF DELPHI2009_UP}
+{$HIGHCHARUNICODE OFF}
+{$ENDIF}
+
+{ }
+{ Compiler warnings }
+{ }
+{$IFDEF DELPHI7}
+{$WARN UNSAFE_CODE OFF}
+{$WARN UNSAFE_TYPE OFF}
+{$WARN UNSAFE_CAST OFF}
+{$ENDIF}
+
+{$IFDEF DELPHI2007}
+{$IFNDEF DOT_NET}
+{$WARN UNSAFE_CODE OFF}
+{$WARN UNSAFE_TYPE OFF}
+{$WARN UNSAFE_CAST OFF}
+{$ENDIF}
+{$ENDIF}
+
+{$IFDEF DOT_NET}
+{$WARN UNIT_PLATFORM OFF}
+{$ENDIF}
+
+{$IFNDEF DEBUG}
+{$IFDEF DELPHI6_UP}
+{$WARN SYMBOL_PLATFORM OFF}
+{$WARN UNIT_PLATFORM OFF}
+{$WARN UNIT_DEPRECATED OFF}
+{$ENDIF}
+{$ENDIF}
+
+interface
+
+uses
+ WinApi.Windows,
+ System.SysUtils,
+ EvilWorks.System.SysUtils;
+
+{ }
+{ Hash digests }
+{ }
+type
+ Word64 = packed record
+ case Integer of
+ 0:
+ (Bytes: array [0 .. 7] of Byte);
+ 1:
+ (Words: array [0 .. 3] of Word);
+ 2:
+ (LongWords: array [0 .. 1] of LongWord);
+ end;
+
+ PWord64 = ^Word64;
+
+ T128BitDigest = record
+ case integer of
+ 0:
+ (Int64s: array [0 .. 1] of Int64);
+ 1:
+ (Longs: array [0 .. 3] of LongWord);
+ 2:
+ (Words: array [0 .. 7] of Word);
+ 3:
+ (Bytes: array [0 .. 15] of Byte);
+ end;
+
+ P128BitDigest = ^T128BitDigest;
+
+ T160BitDigest = record
+ case integer of
+ 0:
+ (Longs: array [0 .. 4] of LongWord);
+ 1:
+ (Words: array [0 .. 9] of Word);
+ 2:
+ (Bytes: array [0 .. 19] of Byte);
+ end;
+
+ P160BitDigest = ^T160BitDigest;
+
+ T224BitDigest = record
+ case integer of
+ 0:
+ (Longs: array [0 .. 6] of LongWord);
+ 1:
+ (Words: array [0 .. 13] of Word);
+ 2:
+ (Bytes: array [0 .. 27] of Byte);
+ end;
+
+ P224BitDigest = ^T224BitDigest;
+
+ T256BitDigest = record
+ case integer of
+ 0:
+ (Longs: array [0 .. 7] of LongWord);
+ 1:
+ (Words: array [0 .. 15] of Word);
+ 2:
+ (Bytes: array [0 .. 31] of Byte);
+ end;
+
+ P256BitDigest = ^T256BitDigest;
+
+ T384BitDigest = record
+ case integer of
+ 0:
+ (Word64s: array [0 .. 5] of Word64);
+ 1:
+ (Longs: array [0 .. 11] of LongWord);
+ 2:
+ (Words: array [0 .. 23] of Word);
+ 3:
+ (Bytes: array [0 .. 47] of Byte);
+ end;
+
+ P384BitDigest = ^T384BitDigest;
+
+ T512BitDigest = record
+ case integer of
+ 0:
+ (Word64s: array [0 .. 7] of Word64);
+ 1:
+ (Longs: array [0 .. 15] of LongWord);
+ 2:
+ (Words: array [0 .. 31] of Word);
+ 3:
+ (Bytes: array [0 .. 63] of Byte);
+ end;
+
+ P512BitDigest = ^T512BitDigest;
+ T512BitBuf = array [0 .. 63] of Byte;
+ T1024BitBuf = array [0 .. 127] of Byte;
+
+const
+ MaxHashDigestSize = Sizeof(T160BitDigest);
+
+procedure DigestToHexBufA(const Digest; const Size: Integer; const Buf);
+procedure DigestToHexBufW(const Digest; const Size: Integer; const Buf);
+function DigestToHexA(const Digest; const Size: Integer): AnsiString;
+function DigestToHexW(const Digest; const Size: Integer): WideString;
+function Digest128Equal(const Digest1, Digest2: T128BitDigest): Boolean;
+function Digest160Equal(const Digest1, Digest2: T160BitDigest): Boolean;
+function Digest224Equal(const Digest1, Digest2: T224BitDigest): Boolean;
+function Digest256Equal(const Digest1, Digest2: T256BitDigest): Boolean;
+function Digest384Equal(const Digest1, Digest2: T384BitDigest): Boolean;
+function Digest512Equal(const Digest1, Digest2: T512BitDigest): Boolean;
+
+{ }
+{ Hash errors }
+{ }
+const
+ hashNoError = 0;
+ hashInternalError = 1;
+ hashInvalidHashType = 2;
+ hashInvalidBuffer = 3;
+ hashInvalidBufferSize = 4;
+ hashInvalidDigest = 5;
+ hashInvalidKey = 6;
+ hashInvalidFileName = 7;
+ hashFileOpenError = 8;
+ hashFileSeekError = 9;
+ hashFileReadError = 10;
+ hashNotKeyedHashType = 11;
+ hashTooManyOpenHandles = 12;
+ hashInvalidHandle = 13;
+ hashMAX_ERROR = 13;
+
+function GetHashErrorMessage(const ErrorCode: LongWord): PChar;
+
+type
+ EHashError = class(Exception)
+ protected
+ FErrorCode: LongWord;
+
+ public
+ constructor Create(const ErrorCode: LongWord; const Msg: string = '');
+ property ErrorCode: LongWord read FErrorCode;
+ end;
+
+{ }
+{ Secure memory clear }
+{ Used to clear keys and other sensitive data from memory }
+{ }
+procedure SecureClear(var Buf; const BufSize: Integer);
+procedure SecureClear512(var Buf: T512BitBuf);
+procedure SecureClear1024(var Buf: T1024BitBuf);
+procedure SecureClearStrA(var S: AnsiString);
+procedure SecureClearStrW(var S: WideString);
+
+{ }
+{ Checksum hashing }
+{ }
+function CalcChecksum32(const Buf; const BufSize: Integer): LongWord; overload;
+function CalcChecksum32(const Buf: AnsiString): LongWord; overload;
+
+{ }
+{ XOR hashing }
+{ }
+function CalcXOR8(const Buf; const BufSize: Integer): Byte; overload;
+function CalcXOR8(const Buf: AnsiString): Byte; overload;
+
+function CalcXOR16(const Buf; const BufSize: Integer): Word; overload;
+function CalcXOR16(const Buf: AnsiString): Word; overload;
+
+function CalcXOR32(const Buf; const BufSize: Integer): LongWord; overload;
+function CalcXOR32(const Buf: AnsiString): LongWord; overload;
+
+{ }
+{ CRC 16 hashing }
+{ }
+{ The theory behind CCITT V.41 CRCs: }
+{ }
+{ 1. Select the magnitude of the CRC to be used (typically 16 or 32 }
+{ bits) and choose the polynomial to use. In the case of 16 bit }
+{ CRCs, the CCITT polynomial is recommended and is }
+{ }
+{ 16 12 5 }
+{ G(x) = x + x + x + 1 }
+{ }
+{ This polynomial traps 100% of 1 bit, 2 bit, odd numbers of bit }
+{ errors, 100% of <= 16 bit burst errors and over 99% of all }
+{ other errors. }
+{ }
+{ 2. The CRC is calculated as }
+{ r }
+{ D(x) = (M(x) * 2 ) mod G(x) }
+{ }
+{ This may be better described as : Add r bits (0 content) to }
+{ the end of M(x). Divide this by G(x) and the remainder is the }
+{ CRC. }
+{ }
+{ 3. Tag the CRC onto the end of M(x). }
+{ }
+{ 4. To check it, calculate the CRC of the new message D(x), using }
+{ the same process as in 2. above. The newly calculated CRC }
+{ should be zero. }
+{ }
+{ This effectively means that using CRCs, it is possible to calculate a }
+{ series of bits to tag onto the data which makes the data an exact }
+{ multiple of the polynomial. }
+{ }
+procedure CRC16Init(var CRC16: Word);
+function CRC16Byte(const CRC16: Word; const Octet: Byte): Word;
+function CRC16Buf(const CRC16: Word; const Buf; const BufSize: Integer): Word;
+
+function CalcCRC16(const Buf; const BufSize: Integer): Word; overload;
+function CalcCRC16(const Buf: AnsiString): Word; overload;
+
+{ }
+{ CRC 32 hashing }
+{ }
+procedure SetCRC32Poly(const Poly: LongWord);
+
+procedure CRC32Init(var CRC32: LongWord);
+function CRC32Byte(const CRC32: LongWord; const Octet: Byte): LongWord;
+function CRC32Buf(const CRC32: LongWord; const Buf; const BufSize: Integer): LongWord;
+function CRC32BufNoCase(const CRC32: LongWord; const Buf; const BufSize: Integer): LongWord;
+
+function CalcCRC32(const Buf; const BufSize: Integer): LongWord; overload;
+function CalcCRC32(const Buf: AnsiString): LongWord; overload;
+
+{ }
+{ Adler 32 hashing }
+{ }
+procedure Adler32Init(var Adler32: LongWord);
+function Adler32Byte(const Adler32: LongWord; const Octet: Byte): LongWord;
+function Adler32Buf(const Adler32: LongWord; const Buf; const BufSize: Integer): LongWord;
+
+function CalcAdler32(const Buf; const BufSize: Integer): LongWord; overload;
+function CalcAdler32(const Buf: AnsiString): LongWord; overload;
+
+{ }
+{ ELF hashing }
+{ }
+procedure ELFInit(var Digest: LongWord);
+function ELFBuf(const Digest: LongWord; const Buf; const BufSize: Integer): LongWord;
+
+function CalcELF(const Buf; const BufSize: Integer): LongWord; overload;
+function CalcELF(const Buf: AnsiString): LongWord; overload;
+
+{ }
+{ ISBN checksum }
+{ }
+function IsValidISBN(const S: AnsiString): Boolean;
+
+{ }
+{ LUHN checksum }
+{ }
+{ The LUHN forumula (also known as mod-10) is used in major credit card }
+{ account numbers for validity checking. }
+{ }
+function IsValidLUHN(const S: AnsiString): Boolean;
+
+{ }
+{ Knuth hash }
+{ General purpose string hashing function proposed by Donald E Knuth in }
+{ 'The Art of Computer Programming Vol 3'. }
+{ }
+function KnuthHashA(const S: AnsiString): LongWord;
+function KnuthHashW(const S: WideString): LongWord;
+
+{ }
+{ MD5 hash }
+{ }
+{ MD5 is an Internet standard secure hashing function, that was }
+{ developed by Professor Ronald L. Rivest in 1991. Subsequently it has }
+{ been placed in the public domain. }
+{ MD5 was developed to be more secure after MD4 was 'broken'. }
+{ Den Boer and Bosselaers estimate that if a custom machine were to be }
+{ built specifically to find collisions for MD5 (costing $10m in 1994) it }
+{ would on average take 24 days to find a collision. }
+{ }
+procedure MD5InitDigest(var Digest: T128BitDigest);
+procedure MD5Buf(var Digest: T128BitDigest; const Buf; const BufSize: Integer);
+procedure MD5FinalBuf(var Digest: T128BitDigest; const Buf; const BufSize: Integer;
+ const TotalSize: Int64);
+
+function CalcMD5(const Buf; const BufSize: Integer): T128BitDigest; overload;
+function CalcMD5(const Buf: AnsiString): T128BitDigest; overload;
+
+function MD5DigestToStrA(const Digest: T128BitDigest): AnsiString;
+function MD5DigestToHexA(const Digest: T128BitDigest): AnsiString;
+function MD5DigestToHexW(const Digest: T128BitDigest): WideString;
+
+{ }
+{ SHA1 Hashing }
+{ }
+{ Specification at http://www.itl.nist.gov/fipspubs/fip180-1.htm }
+{ Also see RFC 3174. }
+{ SHA1 was developed by NIST and is specified in the Secure Hash Standard }
+{ (SHS, FIPS 180) and corrects an unpublished flaw the original SHA }
+{ algorithm. }
+{ SHA1 produces a 160-bit digest and is considered more secure than MD5. }
+{ SHA1 has a similar design to the MD4-family of hash functions. }
+{ }
+procedure SHA1InitDigest(var Digest: T160BitDigest);
+procedure SHA1Buf(var Digest: T160BitDigest; const Buf; const BufSize: Integer);
+procedure SHA1FinalBuf(var Digest: T160BitDigest; const Buf; const BufSize: Integer;
+ const TotalSize: Int64);
+
+function CalcSHA1(const Buf; const BufSize: Integer): T160BitDigest; overload;
+function CalcSHA1(const Buf: AnsiString): T160BitDigest; overload;
+
+function SHA1DigestToStrA(const Digest: T160BitDigest): AnsiString;
+function SHA1DigestToHexA(const Digest: T160BitDigest): AnsiString;
+function SHA1DigestToHexW(const Digest: T160BitDigest): WideString;
+
+{ }
+{ SHA224 Hashing }
+{ }
+{ 224 bit SHA-2 hash }
+{ http://en.wikipedia.org/wiki/SHA-2 }
+{ SHA-224 is based on SHA-256 }
+{ }
+procedure SHA224InitDigest(var Digest: T256BitDigest);
+procedure SHA224Buf(var Digest: T256BitDigest; const Buf; const BufSize: Integer);
+procedure SHA224FinalBuf(var Digest: T256BitDigest; const Buf; const BufSize: Integer; const TotalSize: Int64;
+ var OutDigest: T224BitDigest);
+
+function CalcSHA224(const Buf; const BufSize: Integer): T224BitDigest; overload;
+function CalcSHA224(const Buf: AnsiString): T224BitDigest; overload;
+
+function SHA224DigestToStrA(const Digest: T224BitDigest): AnsiString;
+function SHA224DigestToHexA(const Digest: T224BitDigest): AnsiString;
+function SHA224DigestToHexW(const Digest: T224BitDigest): WideString;
+
+{ }
+{ SHA256 Hashing }
+{ 256 bit SHA-2 hash }
+{ }
+procedure SHA256InitDigest(var Digest: T256BitDigest);
+procedure SHA256Buf(var Digest: T256BitDigest; const Buf; const BufSize: Integer);
+procedure SHA256FinalBuf(var Digest: T256BitDigest; const Buf; const BufSize: Integer; const TotalSize: Int64);
+
+function CalcSHA256(const Buf; const BufSize: Integer): T256BitDigest; overload;
+function CalcSHA256(const Buf: AnsiString): T256BitDigest; overload;
+
+function SHA256DigestToStrA(const Digest: T256BitDigest): AnsiString;
+function SHA256DigestToHexA(const Digest: T256BitDigest): AnsiString;
+function SHA256DigestToHexW(const Digest: T256BitDigest): WideString;
+
+{ }
+{ SHA384 Hashing }
+{ 384 bit SHA-2 hash }
+{ SHA-384 is based on SHA-512 }
+{ }
+procedure SHA384InitDigest(var Digest: T512BitDigest);
+procedure SHA384Buf(var Digest: T512BitDigest; const Buf; const BufSize: Integer);
+procedure SHA384FinalBuf(var Digest: T512BitDigest; const Buf; const BufSize: Integer; const TotalSize: Int64; var OutDigest: T384BitDigest);
+
+function CalcSHA384(const Buf; const BufSize: Integer): T384BitDigest; overload;
+function CalcSHA384(const Buf: AnsiString): T384BitDigest; overload;
+
+function SHA384DigestToStrA(const Digest: T384BitDigest): AnsiString;
+function SHA384DigestToHexA(const Digest: T384BitDigest): AnsiString;
+function SHA384DigestToHexW(const Digest: T384BitDigest): WideString;
+
+{ }
+{ SHA512 Hashing }
+{ 512 bit SHA-2 hash }
+{ }
+procedure SHA512InitDigest(var Digest: T512BitDigest);
+procedure SHA512Buf(var Digest: T512BitDigest; const Buf; const BufSize: Integer);
+procedure SHA512FinalBuf(var Digest: T512BitDigest; const Buf; const BufSize: Integer; const TotalSize: Int64);
+
+function CalcSHA512(const Buf; const BufSize: Integer): T512BitDigest; overload;
+function CalcSHA512(const Buf: AnsiString): T512BitDigest; overload;
+
+function SHA512DigestToStrA(const Digest: T512BitDigest): AnsiString;
+function SHA512DigestToHexA(const Digest: T512BitDigest): AnsiString;
+function SHA512DigestToHexW(const Digest: T512BitDigest): WideString;
+
+{ }
+{ HMAC-MD5 keyed hashing }
+{ }
+{ HMAC allows secure keyed hashing (hashing with a password). }
+{ HMAC was designed to meet the requirements of the IPSEC working group in }
+{ the IETF, and is now a standard. }
+{ HMAC, are proven to be secure as long as the underlying hash function }
+{ has some reasonable cryptographic strengths. }
+{ See RFC 2104 for details on HMAC. }
+{ }
+procedure HMAC_MD5Init(const Key: Pointer; const KeySize: Integer;
+ var Digest: T128BitDigest; var K: T512BitBuf);
+procedure HMAC_MD5Buf(var Digest: T128BitDigest; const Buf; const BufSize: Integer);
+procedure HMAC_MD5FinalBuf(const K: T512BitBuf; var Digest: T128BitDigest;
+ const Buf; const BufSize: Integer; const TotalSize: Int64);
+
+function CalcHMAC_MD5(const Key: Pointer; const KeySize: Integer;
+ const Buf; const BufSize: Integer): T128BitDigest; overload;
+function CalcHMAC_MD5(const Key: AnsiString; const Buf; const BufSize: Integer): T128BitDigest; overload;
+function CalcHMAC_MD5(const Key, Buf: AnsiString): T128BitDigest; overload;
+
+{ }
+{ HMAC-SHA1 keyed hashing }
+{ }
+procedure HMAC_SHA1Init(const Key: Pointer; const KeySize: Integer;
+ var Digest: T160BitDigest; var K: T512BitBuf);
+procedure HMAC_SHA1Buf(var Digest: T160BitDigest; const Buf; const BufSize: Integer);
+procedure HMAC_SHA1FinalBuf(const K: T512BitBuf; var Digest: T160BitDigest;
+ const Buf; const BufSize: Integer; const TotalSize: Int64);
+
+function CalcHMAC_SHA1(const Key: Pointer; const KeySize: Integer;
+ const Buf; const BufSize: Integer): T160BitDigest; overload;
+function CalcHMAC_SHA1(const Key: AnsiString; const Buf; const BufSize: Integer): T160BitDigest; overload;
+function CalcHMAC_SHA1(const Key, Buf: AnsiString): T160BitDigest; overload;
+
+{ }
+{ HMAC-SHA256 keyed hashing }
+{ }
+procedure HMAC_SHA256Init(const Key: Pointer; const KeySize: Integer;
+ var Digest: T256BitDigest; var K: T512BitBuf);
+procedure HMAC_SHA256Buf(var Digest: T256BitDigest; const Buf; const BufSize: Integer);
+procedure HMAC_SHA256FinalBuf(const K: T512BitBuf; var Digest: T256BitDigest;
+ const Buf; const BufSize: Integer; const TotalSize: Int64);
+
+function CalcHMAC_SHA256(const Key: Pointer; const KeySize: Integer;
+ const Buf; const BufSize: Integer): T256BitDigest; overload;
+function CalcHMAC_SHA256(const Key: AnsiString; const Buf; const BufSize: Integer): T256BitDigest; overload;
+function CalcHMAC_SHA256(const Key, Buf: AnsiString): T256BitDigest; overload;
+
+{ }
+{ HMAC-SHA512 keyed hashing }
+{ }
+procedure HMAC_SHA512Init(const Key: Pointer; const KeySize: Integer; var Digest: T512BitDigest; var K: T1024BitBuf);
+procedure HMAC_SHA512Buf(var Digest: T512BitDigest; const Buf; const BufSize: Integer);
+procedure HMAC_SHA512FinalBuf(const K: T1024BitBuf; var Digest: T512BitDigest; const Buf; const BufSize: Integer; const TotalSize: Int64);
+
+function CalcHMAC_SHA512(const Key: Pointer; const KeySize: Integer;
+ const Buf; const BufSize: Integer): T512BitDigest; overload;
+function CalcHMAC_SHA512(const Key: AnsiString; const Buf; const BufSize: Integer): T512BitDigest; overload;
+function CalcHMAC_SHA512(const Key, Buf: AnsiString): T512BitDigest; overload;
+
+{ }
+{ Hash class wrappers }
+{ }
+type
+ { AHash }
+ { Base class for hash classes. }
+ AHash = class
+ protected
+ FDigest : Pointer;
+ FTotalSize: Int64;
+
+ procedure InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer); virtual; abstract;
+ procedure ProcessBuf(const Buf; const BufSize: Integer); virtual; abstract;
+ procedure ProcessFinalBuf(const Buf; const BufSize: Integer; const TotalSize: Int64); virtual;
+
+ public
+ class function DigestSize: Integer; virtual; abstract;
+ class function BlockSize: Integer; virtual;
+
+ procedure Init(const Digest: Pointer; const Key: Pointer = nil;
+ const KeySize: Integer = 0); overload;
+ procedure Init(const Digest: Pointer; const Key: AnsiString = ''); overload;
+
+ procedure HashBuf(const Buf; const BufSize: Integer; const FinalBuf: Boolean);
+ procedure HashFile(const FileName: string; const Offset: Int64 = 0;
+ const MaxCount: Int64 = - 1);
+ end;
+
+ THashClass = class of AHash;
+
+ { TChecksum32Hash }
+ TChecksum32Hash = class(AHash)
+ protected
+ procedure InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer); override;
+ procedure ProcessBuf(const Buf; const BufSize: Integer); override;
+
+ public
+ class function DigestSize: Integer; override;
+ end;
+
+ { TXOR8Hash }
+ TXOR8Hash = class(AHash)
+ protected
+ procedure InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer); override;
+ procedure ProcessBuf(const Buf; const BufSize: Integer); override;
+
+ public
+ class function DigestSize: Integer; override;
+ end;
+
+ { TXOR16Hash }
+ TXOR16Hash = class(AHash)
+ protected
+ procedure InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer); override;
+ procedure ProcessBuf(const Buf; const BufSize: Integer); override;
+
+ public
+ class function DigestSize: Integer; override;
+ end;
+
+ { TXOR32Hash }
+ TXOR32Hash = class(AHash)
+ protected
+ procedure InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer); override;
+ procedure ProcessBuf(const Buf; const BufSize: Integer); override;
+
+ public
+ class function DigestSize: Integer; override;
+ end;
+
+ { TCRC16Hash }
+ TCRC16Hash = class(AHash)
+ protected
+ procedure InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer); override;
+ procedure ProcessBuf(const Buf; const BufSize: Integer); override;
+
+ public
+ class function DigestSize: Integer; override;
+ end;
+
+ { TCRC32Hash }
+ TCRC32Hash = class(AHash)
+ protected
+ procedure InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer); override;
+ procedure ProcessBuf(const Buf; const BufSize: Integer); override;
+
+ public
+ class function DigestSize: Integer; override;
+ end;
+
+ { TAdler32Hash }
+ TAdler32Hash = class(AHash)
+ protected
+ procedure InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer); override;
+ procedure ProcessBuf(const Buf; const BufSize: Integer); override;
+
+ public
+ class function DigestSize: Integer; override;
+ end;
+
+ { TELFHash }
+ TELFHash = class(AHash)
+ protected
+ procedure InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer); override;
+ procedure ProcessBuf(const Buf; const BufSize: Integer); override;
+
+ public
+ class function DigestSize: Integer; override;
+ end;
+
+ { TMD5Hash }
+ TMD5Hash = class(AHash)
+ protected
+ procedure InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer); override;
+ procedure ProcessBuf(const Buf; const BufSize: Integer); override;
+ procedure ProcessFinalBuf(const Buf; const BufSize: Integer; const TotalSize: Int64); override;
+
+ public
+ class function DigestSize: Integer; override;
+ class function BlockSize: Integer; override;
+ end;
+
+ { TSHA1Hash }
+ TSHA1Hash = class(AHash)
+ protected
+ procedure InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer); override;
+ procedure ProcessBuf(const Buf; const BufSize: Integer); override;
+ procedure ProcessFinalBuf(const Buf; const BufSize: Integer; const TotalSize: Int64); override;
+
+ public
+ class function DigestSize: Integer; override;
+ class function BlockSize: Integer; override;
+ end;
+
+ { TSHA256Hash }
+ TSHA256Hash = class(AHash)
+ protected
+ procedure InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer); override;
+ procedure ProcessBuf(const Buf; const BufSize: Integer); override;
+ procedure ProcessFinalBuf(const Buf; const BufSize: Integer; const TotalSize: Int64); override;
+
+ public
+ class function DigestSize: Integer; override;
+ class function BlockSize: Integer; override;
+ end;
+
+ { TSHA512Hash }
+ TSHA512Hash = class(AHash)
+ protected
+ procedure InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer); override;
+ procedure ProcessBuf(const Buf; const BufSize: Integer); override;
+ procedure ProcessFinalBuf(const Buf; const BufSize: Integer; const TotalSize: Int64); override;
+
+ public
+ class function DigestSize: Integer; override;
+ class function BlockSize: Integer; override;
+ end;
+
+ { THMAC_MD5Hash }
+ THMAC_MD5Hash = class(AHash)
+ protected
+ FKey: T512BitBuf;
+
+ procedure InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer); override;
+ procedure ProcessBuf(const Buf; const BufSize: Integer); override;
+ procedure ProcessFinalBuf(const Buf; const BufSize: Integer; const TotalSize: Int64); override;
+
+ public
+ class function DigestSize: Integer; override;
+ class function BlockSize: Integer; override;
+
+ destructor Destroy; override;
+ end;
+
+ { THMAC_SHA1Hash }
+ THMAC_SHA1Hash = class(AHash)
+ protected
+ FKey: T512BitBuf;
+
+ procedure InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer); override;
+ procedure ProcessBuf(const Buf; const BufSize: Integer); override;
+ procedure ProcessFinalBuf(const Buf; const BufSize: Integer; const TotalSize: Int64); override;
+
+ public
+ class function DigestSize: Integer; override;
+ class function BlockSize: Integer; override;
+
+ destructor Destroy; override;
+ end;
+
+ { THMAC_SHA256Hash }
+ THMAC_SHA256Hash = class(AHash)
+ protected
+ FKey: T512BitBuf;
+
+ procedure InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer); override;
+ procedure ProcessBuf(const Buf; const BufSize: Integer); override;
+ procedure ProcessFinalBuf(const Buf; const BufSize: Integer; const TotalSize: Int64); override;
+
+ public
+ class function DigestSize: Integer; override;
+ class function BlockSize: Integer; override;
+
+ destructor Destroy; override;
+ end;
+
+ { THMAC_SHA512Hash }
+ THMAC_SHA512Hash = class(AHash)
+ protected
+ FKey: T1024BitBuf;
+
+ procedure InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer); override;
+ procedure ProcessBuf(const Buf; const BufSize: Integer); override;
+ procedure ProcessFinalBuf(const Buf; const BufSize: Integer; const TotalSize: Int64); override;
+
+ public
+ class function DigestSize: Integer; override;
+ class function BlockSize: Integer; override;
+
+ destructor Destroy; override;
+ end;
+
+{ }
+{ THashType }
+{ }
+type
+ THashType = (
+ hashChecksum32, hashXOR8, hashXOR16, hashXOR32,
+ hashCRC16, hashCRC32,
+ hashAdler32,
+ hashELF,
+ hashMD5, hashSHA1, hashSHA256, hashSHA512,
+ hashHMAC_MD5, hashHMAC_SHA1, hashHMAC_SHA256, hashHMAC_SHA512);
+
+{ }
+{ GetHashClassByType }
+{ }
+function GetHashClassByType(const HashType: THashType): THashClass;
+function GetDigestSize(const HashType: THashType): Integer;
+
+{ }
+{ CalculateHash }
+{ }
+procedure CalculateHash(const HashType: THashType;
+ const Buf; const BufSize: Integer; const Digest: Pointer;
+ const Key: Pointer = nil; const KeySize: Integer = 0); overload;
+procedure CalculateHash(const HashType: THashType;
+ const Buf; const BufSize: Integer;
+ const Digest: Pointer; const Key: AnsiString = ''); overload;
+procedure CalculateHash(const HashType: THashType;
+ const Buf: AnsiString; const Digest: Pointer;
+ const Key: AnsiString = ''); overload;
+
+{ }
+{ HashString }
+{ }
+{ HashString is a fast general purpose ASCII string hashing function. }
+{ It returns a 32 bit value in the range 0 to Slots - 1. If Slots = 0 then }
+{ the full 32 bit value is returned. }
+{ If CaseSensitive = False then HashString will return the same hash value }
+{ regardless of the case of the characters in the string. }
+{ }
+{ The implementation is based on CRC32. It uses up to 48 characters from }
+{ the string (first 16 characters, last 16 characters and 16 characters }
+{ uniformly sampled from the remaining characters) to calculate the hash }
+{ value. }
+{ }
+function HashString(const StrBuf: Pointer; const StrLength: Integer;
+ const Slots: LongWord = 0; const CaseSensitive: Boolean = True): LongWord; overload;
+function HashString(const S: AnsiString; const Slots: LongWord = 0;
+ const CaseSensitive: Boolean = True): LongWord; overload;
+
+implementation
+
+{ }
+{ Hash errors }
+{ }
+const
+ hashErrorMessages: array [0 .. hashMAX_ERROR] of string = (
+ '',
+ 'Internal error',
+ 'Invalid hash type',
+ 'Invalid buffer',
+ 'Invalid buffer size',
+ 'Invalid digest',
+ 'Invalid key',
+ 'Invalid file name',
+ 'File open error',
+ 'File seek error',
+ 'File read error',
+ 'Not a keyed hash type',
+ 'Too many open handles',
+ 'Invalid handle');
+
+function GetHashErrorMessage(const ErrorCode: LongWord): PChar;
+begin
+ if (ErrorCode = hashNoError) or (ErrorCode > hashMAX_ERROR) then
+ Result := nil
+ else
+ Result := PChar(hashErrorMessages[ErrorCode]);
+end;
+
+{ }
+{ EHashError }
+{ }
+constructor EHashError.Create(const ErrorCode: LongWord; const Msg: string);
+begin
+ FErrorCode := ErrorCode;
+ if (Msg = '') and (ErrorCode <= hashMAX_ERROR) then
+ inherited Create(hashErrorMessages[ErrorCode])
+ else
+ inherited Create(Msg);
+end;
+
+{ }
+{ Secure memory clear }
+{ }
+procedure SecureClear(var Buf; const BufSize: Integer);
+begin
+ if BufSize <= 0 then
+ exit;
+ FillChar(Buf, BufSize, #$00);
+end;
+
+procedure SecureClear512(var Buf: T512BitBuf);
+begin
+ SecureClear(Buf, SizeOf(Buf));
+end;
+
+procedure SecureClear1024(var Buf: T1024BitBuf);
+begin
+ SecureClear(Buf, SizeOf(Buf));
+end;
+
+procedure SecureClearStrA(var S: AnsiString);
+var
+ L: Integer;
+begin
+ L := Length(S);
+ if L = 0 then
+ exit;
+ SecureClear(S[1], L);
+ S := '';
+end;
+
+procedure SecureClearStrW(var S: WideString);
+var
+ L: Integer;
+begin
+ L := Length(S);
+ if L = 0 then
+ exit;
+ SecureClear(S[1], L * SizeOf(WideChar));
+ S := '';
+end;
+
+{ }
+{ Checksum hashing }
+{ }
+{$IFDEF ASM386_DELPHI}
+
+
+function CalcChecksum32(const Buf; const BufSize: Integer): LongWord;
+asm
+ or eax, eax //eax = Buf
+ jz @fin
+ or edx, edx //edx = BufSize
+ jbe @finz
+ push esi
+ mov esi, eax
+ add esi, edx
+ xor eax, eax
+ xor ecx, ecx
+@l1:
+ dec esi
+ mov cl, [esi]
+ add eax, ecx
+ dec edx
+ jnz @l1
+ pop esi
+@fin:
+ ret
+@finz:
+ xor eax, eax
+end;
+{$ELSE}
+
+
+function CalcChecksum32(const Buf; const BufSize: Integer): LongWord;
+var
+ I: Integer;
+ P: PByte;
+begin
+ Result := 0;
+ P := @Buf;
+ for I := 1 to BufSize do
+ begin
+ Inc(Result, P^);
+ Inc(P);
+ end;
+end;
+{$ENDIF}
+
+
+function CalcChecksum32(const Buf: AnsiString): LongWord;
+begin
+ Result := CalcChecksum32(Pointer(Buf)^, Length(Buf));
+end;
+
+{ }
+{ XOR hashing }
+{ }
+{$IFDEF ASM386_DELPHI}
+
+
+function XOR32Buf(const Buf; const BufSize: Integer): LongWord;
+Asm
+ or eax, eax
+ jz @fin
+ or edx, edx
+ jz @finz
+
+ push esi
+ mov esi, eax
+ xor eax, eax
+
+ mov ecx, edx
+ shr ecx, 2
+ jz @rest
+
+@l1:
+ xor eax, [esi]
+ add esi, 4
+ dec ecx
+ jnz @l1
+
+@rest:
+ and edx, 3
+ jz @finp
+ xor al, [esi]
+ dec edx
+ jz @finp
+ inc esi
+ xor ah, [esi]
+ dec edx
+ jz @finp
+ inc esi
+ mov dl, [esi]
+ shl edx, 16
+ xor eax, edx
+
+@finp:
+ pop esi
+ ret
+@finz:
+ xor eax, eax
+@fin:
+ ret
+end;
+{$ELSE}
+
+
+function XOR32Buf(const Buf; const BufSize: Integer): LongWord;
+var
+ I: Integer;
+ L: Byte;
+ P: PAnsiChar;
+begin
+ Result := 0;
+ L := 0;
+ P := @Buf;
+ for I := 1 to BufSize do
+ begin
+ Result := Result xor (Byte(P^) shl L);
+ Inc(L, 8);
+ if L = 32 then
+ L := 0;
+ Inc(P);
+ end;
+end;
+{$ENDIF}
+
+
+function CalcXOR8(const Buf; const BufSize: Integer): Byte;
+var
+ L: LongWord;
+begin
+ L := XOR32Buf(Buf, BufSize);
+ Result := Byte(L) xor
+ Byte(L shr 8) xor
+ Byte(L shr 16) xor
+ Byte(L shr 24);
+end;
+
+function CalcXOR8(const Buf: AnsiString): Byte;
+begin
+ Result := CalcXOR8(Pointer(Buf)^, Length(Buf));
+end;
+
+function CalcXOR16(const Buf; const BufSize: Integer): Word;
+var
+ L: LongWord;
+begin
+ L := XOR32Buf(Buf, BufSize);
+ Result := Word(L) xor
+ Word(L shr 16);
+end;
+
+function CalcXOR16(const Buf: AnsiString): Word;
+begin
+ Result := CalcXOR16(Pointer(Buf)^, Length(Buf));
+end;
+
+function CalcXOR32(const Buf; const BufSize: Integer): LongWord;
+begin
+ Result := XOR32Buf(Buf, BufSize);
+end;
+
+function CalcXOR32(const Buf: AnsiString): LongWord;
+begin
+ Result := XOR32Buf(Pointer(Buf)^, Length(Buf));
+end;
+
+{ }
+{ CRC 16 hashing }
+{ }
+const
+ CRC16Table: array [Byte] of Word = (
+ $0000, $1021, $2042, $3063, $4084, $50A5, $60C6, $70E7,
+ $8108, $9129, $A14A, $B16B, $C18C, $D1AD, $E1CE, $F1EF,
+ $1231, $0210, $3273, $2252, $52B5, $4294, $72F7, $62D6,
+ $9339, $8318, $B37B, $A35A, $D3BD, $C39C, $F3FF, $E3DE,
+ $2462, $3443, $0420, $1401, $64E6, $74C7, $44A4, $5485,
+ $A56A, $B54B, $8528, $9509, $E5EE, $F5CF, $C5AC, $D58D,
+ $3653, $2672, $1611, $0630, $76D7, $66F6, $5695, $46B4,
+ $B75B, $A77A, $9719, $8738, $F7DF, $E7FE, $D79D, $C7BC,
+ $48C4, $58E5, $6886, $78A7, $0840, $1861, $2802, $3823,
+ $C9CC, $D9ED, $E98E, $F9AF, $8948, $9969, $A90A, $B92B,
+ $5AF5, $4AD4, $7AB7, $6A96, $1A71, $0A50, $3A33, $2A12,
+ $DBFD, $CBDC, $FBBF, $EB9E, $9B79, $8B58, $BB3B, $AB1A,
+ $6CA6, $7C87, $4CE4, $5CC5, $2C22, $3C03, $0C60, $1C41,
+ $EDAE, $FD8F, $CDEC, $DDCD, $AD2A, $BD0B, $8D68, $9D49,
+ $7E97, $6EB6, $5ED5, $4EF4, $3E13, $2E32, $1E51, $0E70,
+ $FF9F, $EFBE, $DFDD, $CFFC, $BF1B, $AF3A, $9F59, $8F78,
+ $9188, $81A9, $B1CA, $A1EB, $D10C, $C12D, $F14E, $E16F,
+ $1080, $00A1, $30C2, $20E3, $5004, $4025, $7046, $6067,
+ $83B9, $9398, $A3FB, $B3DA, $C33D, $D31C, $E37F, $F35E,
+ $02B1, $1290, $22F3, $32D2, $4235, $5214, $6277, $7256,
+ $B5EA, $A5CB, $95A8, $8589, $F56E, $E54F, $D52C, $C50D,
+ $34E2, $24C3, $14A0, $0481, $7466, $6447, $5424, $4405,
+ $A7DB, $B7FA, $8799, $97B8, $E75F, $F77E, $C71D, $D73C,
+ $26D3, $36F2, $0691, $16B0, $6657, $7676, $4615, $5634,
+ $D94C, $C96D, $F90E, $E92F, $99C8, $89E9, $B98A, $A9AB,
+ $5844, $4865, $7806, $6827, $18C0, $08E1, $3882, $28A3,
+ $CB7D, $DB5C, $EB3F, $FB1E, $8BF9, $9BD8, $ABBB, $BB9A,
+ $4A75, $5A54, $6A37, $7A16, $0AF1, $1AD0, $2AB3, $3A92,
+ $FD2E, $ED0F, $DD6C, $CD4D, $BDAA, $AD8B, $9DE8, $8DC9,
+ $7C26, $6C07, $5C64, $4C45, $3CA2, $2C83, $1CE0, $0CC1,
+ $EF1F, $FF3E, $CF5D, $DF7C, $AF9B, $BFBA, $8FD9, $9FF8,
+ $6E17, $7E36, $4E55, $5E74, $2E93, $3EB2, $0ED1, $1EF0);
+
+function CRC16Byte(const CRC16: Word; const Octet: Byte): Word;
+begin
+ Result := CRC16Table[Byte(Hi(CRC16) xor Octet)] xor Word(CRC16 shl 8);
+end;
+
+function CRC16Buf(const CRC16: Word; const Buf; const BufSize: Integer): Word;
+var
+ I: Integer;
+ P: PByte;
+begin
+ Result := CRC16;
+ P := @Buf;
+ for I := 1 to BufSize do
+ begin
+ Result := CRC16Byte(Result, P^);
+ Inc(P);
+ end;
+end;
+
+procedure CRC16Init(var CRC16: Word);
+begin
+ CRC16 := $FFFF;
+end;
+
+function CalcCRC16(const Buf; const BufSize: Integer): Word;
+begin
+ CRC16Init(Result);
+ Result := CRC16Buf(Result, Buf, BufSize);
+end;
+
+function CalcCRC16(const Buf: AnsiString): Word;
+begin
+ Result := CalcCRC16(Pointer(Buf)^, Length(Buf));
+end;
+
+{ }
+{ CRC 32 hashing }
+{ }
+var
+ CRC32TableInit: Boolean = False;
+ CRC32Table : array [Byte] of LongWord;
+ CRC32Poly : LongWord = $EDB88320;
+
+procedure InitCRC32Table;
+var
+ I, J: Byte;
+ R : LongWord;
+begin
+ for I := $00 to $FF do
+ begin
+ R := I;
+ for J := 8 downto 1 do
+ if R and 1 <> 0 then
+ R := (R shr 1) xor CRC32Poly
+ else
+ R := R shr 1;
+ CRC32Table[I] := R;
+ end;
+ CRC32TableInit := True;
+end;
+
+procedure SetCRC32Poly(const Poly: LongWord);
+begin
+ CRC32Poly := Poly;
+ CRC32TableInit := False;
+end;
+
+function CalcCRC32Byte(const CRC32: LongWord; const Octet: Byte): LongWord; {$IFDEF UseInline}inline; {$ENDIF}
+begin
+ Result := CRC32Table[Byte(CRC32) xor Octet] xor ((CRC32 shr 8) and $00FFFFFF);
+end;
+
+function CRC32Byte(const CRC32: LongWord; const Octet: Byte): LongWord;
+begin
+ if not CRC32TableInit then
+ InitCRC32Table;
+ Result := CalcCRC32Byte(CRC32, Octet);
+end;
+
+function CRC32Buf(const CRC32: LongWord; const Buf; const BufSize: Integer): LongWord;
+var
+ P: PByte;
+ I: Integer;
+begin
+ if not CRC32TableInit then
+ InitCRC32Table;
+ P := @Buf;
+ Result := CRC32;
+ for I := 1 to BufSize do
+ begin
+ Result := CalcCRC32Byte(Result, P^);
+ Inc(P);
+ end;
+end;
+
+function CRC32BufNoCase(const CRC32: LongWord; const Buf; const BufSize: Integer): LongWord;
+var
+ P: PByte;
+ I: Integer;
+ C: Byte;
+begin
+ if not CRC32TableInit then
+ InitCRC32Table;
+ P := @Buf;
+ Result := CRC32;
+ for I := 1 to BufSize do
+ begin
+ C := P^;
+ if AnsiChar(C) in ['A' .. 'Z'] then
+ C := C or 32;
+ Result := CalcCRC32Byte(Result, C);
+ Inc(P);
+ end;
+end;
+
+procedure CRC32Init(var CRC32: LongWord);
+begin
+ CRC32 := $FFFFFFFF;
+end;
+
+function CalcCRC32(const Buf; const BufSize: Integer): LongWord;
+begin
+ CRC32Init(Result);
+ Result := not CRC32Buf(Result, Buf, BufSize);
+end;
+
+function CalcCRC32(const Buf: AnsiString): LongWord;
+begin
+ Result := CalcCRC32(Pointer(Buf)^, Length(Buf));
+end;
+
+{ }
+{ Adler 32 hashing }
+{ }
+procedure Adler32Init(var Adler32: LongWord);
+begin
+ Adler32 := $00000001;
+end;
+
+const
+ Adler32Mod = 65521; // largest prime smaller than 65536
+
+function Adler32Byte(const Adler32: LongWord; const Octet: Byte): LongWord;
+var
+ A, B: LongWord;
+begin
+ A := Adler32 and $0000FFFF;
+ B := Adler32 shr 16;
+ Inc(A, Octet);
+ Inc(B, A);
+ if A >= Adler32Mod then
+ Dec(A, Adler32Mod);
+ if B >= Adler32Mod then
+ Dec(B, Adler32Mod);
+ Result := A or (B shl 16);
+end;
+
+function Adler32Buf(const Adler32: LongWord; const Buf; const BufSize: Integer): LongWord;
+var
+ A, B: LongWord;
+ P : PByte;
+ I : Integer;
+begin
+ A := Adler32 and $0000FFFF;
+ B := Adler32 shr 16;
+ P := @Buf;
+ for I := 1 to BufSize do
+ begin
+ Inc(A, P^);
+ Inc(B, A);
+ if A >= Adler32Mod then
+ Dec(A, Adler32Mod);
+ if B >= Adler32Mod then
+ Dec(B, Adler32Mod);
+ Inc(P);
+ end;
+ Result := A or (B shl 16);
+end;
+
+function CalcAdler32(const Buf; const BufSize: Integer): LongWord;
+begin
+ Adler32Init(Result);
+ Result := Adler32Buf(Result, Buf, BufSize);
+end;
+
+function CalcAdler32(const Buf: AnsiString): LongWord;
+begin
+ Result := CalcAdler32(Pointer(Buf)^, Length(Buf));
+end;
+
+{ }
+{ ELF hashing }
+{ }
+procedure ELFInit(var Digest: LongWord);
+begin
+ Digest := 0;
+end;
+
+function ELFBuf(const Digest: LongWord; const Buf; const BufSize: Integer): LongWord;
+var
+ I: Integer;
+ P: PByte;
+ X: LongWord;
+begin
+ Result := Digest;
+ P := @Buf;
+ for I := 1 to BufSize do
+ begin
+ Result := (Result shl 4) + P^;
+ Inc(P);
+ X := Result and $F0000000;
+ if X <> 0 then
+ Result := Result xor (X shr 24);
+ Result := Result and (not X);
+ end;
+end;
+
+function CalcELF(const Buf; const BufSize: Integer): LongWord;
+begin
+ Result := ELFBuf(0, Buf, BufSize);
+end;
+
+function CalcELF(const Buf: AnsiString): LongWord;
+begin
+ Result := CalcELF(Pointer(Buf)^, Length(Buf));
+end;
+
+{ }
+{ ISBN checksum }
+{ }
+function IsValidISBN(const S: AnsiString): Boolean;
+var
+ I, L, M, D, C: Integer;
+ P : PAnsiChar;
+begin
+ L := Length(S);
+ if L < 10 then // too few digits
+ begin
+ Result := False;
+ exit;
+ end;
+ M := 10;
+ C := 0;
+ P := Pointer(S);
+ for I := 1 to L do
+ begin
+ if (P^ in ['0' .. '9']) or ((M = 1) and (P^ in ['x', 'X'])) then
+ begin
+ if M = 0 then // too many digits
+ begin
+ Result := False;
+ exit;
+ end;
+ if P^ in ['x', 'X'] then
+ D := 10
+ else
+ D := Ord(P^) - Ord('0');
+ Inc(C, M * D);
+ Dec(M);
+ end;
+ Inc(P);
+ end;
+ if M > 0 then // too few digits
+ begin
+ Result := False;
+ exit;
+ end;
+ Result := C mod 11 = 0;
+end;
+
+{ }
+{ LUHN checksum }
+{ }
+function IsValidLUHN(const S: AnsiString): Boolean;
+var
+ P : PAnsiChar;
+ I, L, M, C, D: Integer;
+ R : Boolean;
+begin
+ L := Length(S);
+ if L = 0 then
+ begin
+ Result := False;
+ exit;
+ end;
+ P := Pointer(S);
+ Inc(P, L - 1);
+ C := 0;
+ M := 0;
+ R := False;
+ for I := 1 to L do
+ begin
+ if P^ in ['0' .. '9'] then
+ begin
+ D := Ord(P^) - Ord('0');
+ if R then
+ begin
+ D := D * 2;
+ D := (D div 10) + (D mod 10);
+ end;
+ Inc(C, D);
+ Inc(M);
+ R := not R;
+ end;
+ Dec(P);
+ end;
+ Result := (M >= 1) and (C mod 10 = 0);
+end;
+
+{ }
+{ Knuth Hash }
+{ }
+function KnuthHashA(const S: AnsiString): LongWord;
+var
+ I, L: Integer;
+ H : LongWord;
+begin
+ L := Length(S);
+ H := L;
+ for I := 1 to L do
+ H := ((H shr 5) xor (H shl 27)) xor Ord(S[I]);
+ Result := H;
+end;
+
+function KnuthHashW(const S: WideString): LongWord;
+var
+ I, L: Integer;
+ H : LongWord;
+begin
+ L := Length(S);
+ H := L;
+ for I := 1 to L do
+ H := ((H shr 5) xor (H shl 27)) xor Ord(S[I]);
+ Result := H;
+end;
+
+{ }
+{ Digests }
+{ }
+const
+ s_HexDigitsLower: string[16] = '0123456789abcdef';
+
+procedure DigestToHexBufA(const Digest; const Size: Integer; const Buf);
+var
+ I: Integer;
+ P: PAnsiChar;
+ Q: PByte;
+begin
+ P := @Buf;;
+ Assert(Assigned(P));
+ Q := @Digest;
+ Assert(Assigned(Q));
+ for I := 0 to Size - 1 do
+ begin
+ P^ := s_HexDigitsLower[Q^ shr 4 + 1];
+ Inc(P);
+ P^ := s_HexDigitsLower[Q^ and 15 + 1];
+ Inc(P);
+ Inc(Q);
+ end;
+end;
+
+procedure DigestToHexBufW(const Digest; const Size: Integer; const Buf);
+var
+ I: Integer;
+ P: PWideChar;
+ Q: PByte;
+begin
+ P := @Buf;;
+ Assert(Assigned(P));
+ Q := @Digest;
+ Assert(Assigned(Q));
+ for I := 0 to Size - 1 do
+ begin
+ P^ := WideChar(s_HexDigitsLower[Q^ shr 4 + 1]);
+ Inc(P);
+ P^ := WideChar(s_HexDigitsLower[Q^ and 15 + 1]);
+ Inc(P);
+ Inc(Q);
+ end;
+end;
+
+function DigestToHexA(const Digest; const Size: Integer): AnsiString;
+begin
+ SetLength(Result, Size * 2);
+ DigestToHexBufA(Digest, Size, Pointer(Result)^);
+end;
+
+function DigestToHexW(const Digest; const Size: Integer): WideString;
+begin
+ SetLength(Result, Size * 2);
+ DigestToHexBufW(Digest, Size, Pointer(Result)^);
+end;
+
+function Digest128Equal(const Digest1, Digest2: T128BitDigest): Boolean;
+var
+ I: Integer;
+begin
+ for I := 0 to 3 do
+ if Digest1.Longs[I] <> Digest2.Longs[I] then
+ begin
+ Result := False;
+ exit;
+ end;
+ Result := True;
+end;
+
+function Digest160Equal(const Digest1, Digest2: T160BitDigest): Boolean;
+var
+ I: Integer;
+begin
+ for I := 0 to 4 do
+ if Digest1.Longs[I] <> Digest2.Longs[I] then
+ begin
+ Result := False;
+ exit;
+ end;
+ Result := True;
+end;
+
+function Digest224Equal(const Digest1, Digest2: T224BitDigest): Boolean;
+var
+ I: Integer;
+begin
+ for I := 0 to 6 do
+ if Digest1.Longs[I] <> Digest2.Longs[I] then
+ begin
+ Result := False;
+ exit;
+ end;
+ Result := True;
+end;
+
+function Digest256Equal(const Digest1, Digest2: T256BitDigest): Boolean;
+var
+ I: Integer;
+begin
+ for I := 0 to 7 do
+ if Digest1.Longs[I] <> Digest2.Longs[I] then
+ begin
+ Result := False;
+ exit;
+ end;
+ Result := True;
+end;
+
+function Digest384Equal(const Digest1, Digest2: T384BitDigest): Boolean;
+var
+ I: Integer;
+begin
+ for I := 0 to 11 do
+ if Digest1.Longs[I] <> Digest2.Longs[I] then
+ begin
+ Result := False;
+ exit;
+ end;
+ Result := True;
+end;
+
+function Digest512Equal(const Digest1, Digest2: T512BitDigest): Boolean;
+var
+ I: Integer;
+begin
+ for I := 0 to 15 do
+ if Digest1.Longs[I] <> Digest2.Longs[I] then
+ begin
+ Result := False;
+ exit;
+ end;
+ Result := True;
+end;
+
+{ }
+{ ReverseMem }
+{ Utility function to reverse order of data in buffer. }
+{ }
+procedure ReverseMem(var Buf; const BufSize: Integer);
+var
+ I: Integer;
+ P: PByte;
+ Q: PByte;
+ T: Byte;
+begin
+ P := @Buf;
+ Q := P;
+ Inc(Q, BufSize - 1);
+ for I := 1 to BufSize div 2 do
+ begin
+ T := P^;
+ P^ := Q^;
+ Q^ := T;
+ Inc(P);
+ Dec(Q);
+ end;
+end;
+
+{ }
+{ StdFinalBuf }
+{ Utility function to prepare final buffer(s). }
+{ Fills Buf1 and potentially Buf2 from Buf (FinalBufCount = 1 or 2). }
+{ Used by MD5, SHA1, SHA256, SHA512. }
+{ }
+procedure StdFinalBuf512(
+ const Buf; const BufSize: Integer; const TotalSize: Int64;
+ var Buf1, Buf2: T512BitBuf;
+ var FinalBufs: Integer;
+ const SwapEndian: Boolean);
+var
+ P, Q: PByte;
+ I : Integer;
+ L : Int64;
+begin
+ Assert(BufSize < 64, 'Final BufSize must be less than 64 bytes');
+ Assert(TotalSize >= BufSize, 'TotalSize >= BufSize');
+
+ P := @Buf;
+ Q := @Buf1[0];
+ if BufSize > 0 then
+ begin
+ Move(P^, Q^, BufSize);
+ Inc(Q, BufSize);
+ end;
+ Q^ := $80;
+ Inc(Q);
+
+{$IFDEF DELPHI5}
+ // Delphi 5 sometimes reports fatal error (internal error C1093) when compiling:
+ // L := TotalSize * 8
+ L := TotalSize;
+ L := L * 8;
+{$ELSE}
+ L := TotalSize * 8;
+{$ENDIF}
+ if SwapEndian then
+ ReverseMem(L, 8);
+ if BufSize + 1 > 64 - Sizeof(Int64) then
+ begin
+ FillChar(Q^, 64 - BufSize - 1, #0);
+ Q := @Buf2[0];
+ FillChar(Q^, 64 - Sizeof(Int64), #0);
+ Inc(Q, 64 - Sizeof(Int64));
+ PInt64(Q)^ := L;
+ FinalBufs := 2;
+ end
+ else
+ begin
+ I := 64 - Sizeof(Int64) - BufSize - 1;
+ FillChar(Q^, I, #0);
+ Inc(Q, I);
+ PInt64(Q)^ := L;
+ FinalBufs := 1;
+ end;
+end;
+
+procedure StdFinalBuf1024(
+ const Buf; const BufSize: Integer; const TotalSize: Int64;
+ var Buf1, Buf2: T1024BitBuf;
+ var FinalBufs: Integer;
+ const SwapEndian: Boolean);
+var
+ P, Q: PByte;
+ I : Integer;
+ L : Int64;
+begin
+ Assert(BufSize < 128, 'Final BufSize must be less than 128 bytes');
+ Assert(TotalSize >= BufSize, 'TotalSize >= BufSize');
+
+ P := @Buf;
+ Q := @Buf1[0];
+ if BufSize > 0 then
+ begin
+ Move(P^, Q^, BufSize);
+ Inc(Q, BufSize);
+ end;
+ Q^ := $80;
+ Inc(Q);
+
+{$IFDEF DELPHI5}
+ // Delphi 5 sometimes reports fatal error (internal error C1093) when compiling:
+ // L := TotalSize * 8
+ L := TotalSize;
+ L := L * 8;
+{$ELSE}
+ L := TotalSize * 8;
+{$ENDIF}
+ if SwapEndian then
+ ReverseMem(L, 8);
+ if BufSize + 1 > 128 - Sizeof(Int64) * 2 then
+ begin
+ FillChar(Q^, 128 - BufSize - 1, #0);
+ Q := @Buf2[0];
+ FillChar(Q^, 128 - Sizeof(Int64) * 2, #0);
+ Inc(Q, 128 - Sizeof(Int64) * 2);
+ PInt64(Q)^ := 0;
+ Inc(Q, 8);
+ PInt64(Q)^ := L;
+ FinalBufs := 2;
+ end
+ else
+ begin
+ I := 128 - Sizeof(Int64) * 2 - BufSize - 1;
+ FillChar(Q^, I, #0);
+ Inc(Q, I);
+ PInt64(Q)^ := 0;
+ Inc(Q, 8);
+ PInt64(Q)^ := L;
+ FinalBufs := 1;
+ end;
+end;
+
+{ }
+{ Utility functions SwapEndian, RotateLeftBits, RotateRightBits. }
+{ Used by SHA1 and SHA256. }
+{ }
+{$IFDEF ASM386}
+
+
+function SwapEndian(const Value: LongWord): LongWord; register; assembler;
+asm
+ XCHG AH, AL
+ ROL EAX, 16
+ XCHG AH, AL
+end;
+{$ELSE}
+
+
+function SwapEndian(const Value: LongWord): LongWord;
+begin
+ Result := ((Value and $000000FF) shl 24) or
+ ((Value and $0000FF00) shl 8) or
+ ((Value and $00FF0000) shr 8) or
+ ((Value and $FF000000) shr 24);
+end;
+{$ENDIF}
+
+
+procedure SwapEndianBuf(var Buf; const Count: Integer);
+var
+ P: PLongWord;
+ I: Integer;
+begin
+ P := @Buf;
+ for I := 1 to Count do
+ begin
+ P^ := SwapEndian(P^);
+ Inc(P);
+ end;
+end;
+
+{$IFDEF ASM386_DELPHI}
+
+
+function RotateLeftBits(const Value: LongWord; const Bits: Byte): LongWord;
+asm
+ MOV CL, DL
+ ROL EAX, CL
+end;
+{$ELSE}
+
+
+function RotateLeftBits(const Value: LongWord; const Bits: Byte): LongWord;
+var
+ I: Integer;
+begin
+ Result := Value;
+ for I := 1 to Bits do
+ if Result and $80000000 = 0 then
+ Result := Value shl 1
+ else
+ Result := (Value shl 1) or 1;
+end;
+{$ENDIF}
+
+{$IFDEF ASM386_DELPHI}
+
+
+function RotateRightBits(const Value: LongWord; const Bits: Byte): LongWord;
+asm
+ MOV CL, DL
+ ROR EAX, CL
+end;
+{$ELSE}
+
+
+function RotateRightBits(const Value: LongWord; const Bits: Byte): LongWord;
+var
+ I, B: Integer;
+begin
+ Result := Value;
+ if Bits >= 32 then
+ B := Bits mod 32
+ else
+ B := Bits;
+ for I := 1 to B do
+ if Result and 1 = 0 then
+ Result := Result shr 1
+ else
+ Result := (Result shr 1) or $80000000;
+end;
+{$ENDIF}
+
+
+{ }
+{ Utility functions for Word64 arithmetic }
+{ Used by SHA-512 }
+{ }
+procedure Word64InitZero(var A: Word64);
+begin
+ A.LongWords[0] := 0;
+ A.LongWords[1] := 0;
+end;
+
+procedure Word64Not(var A: Word64);
+begin
+ A.LongWords[0] := not A.LongWords[0];
+ A.LongWords[1] := not A.LongWords[1];
+end;
+
+procedure Word64AndWord64(var A: Word64; const B: Word64);
+begin
+ A.LongWords[0] := A.LongWords[0] and B.LongWords[0];
+ A.LongWords[1] := A.LongWords[1] and B.LongWords[1];
+end;
+
+procedure Word64XorWord64(var A: Word64; const B: Word64);
+begin
+ A.LongWords[0] := A.LongWords[0] xor B.LongWords[0];
+ A.LongWords[1] := A.LongWords[1] xor B.LongWords[1];
+end;
+
+procedure Word64AddWord64(var A: Word64; const B: Word64);
+var
+ C, D: Int64;
+begin
+ C := Int64(A.LongWords[0]) + B.LongWords[0];
+ D := Int64(A.LongWords[1]) + B.LongWords[1];
+ if C >= $100000000 then
+ Inc(D);
+ A.LongWords[0] := C and $FFFFFFFF;
+ A.LongWords[1] := D and $FFFFFFFF;
+end;
+
+procedure Word64Shr(var A: Word64; const B: Byte);
+var
+ C: Byte;
+begin
+ if B = 0 then
+ exit;
+ if B >= 64 then
+ Word64InitZero(A)
+ else
+ if B < 32 then
+ begin
+ C := 32 - B;
+ A.LongWords[0] := (A.LongWords[0] shr B) or (A.LongWords[1] shl C);
+ A.LongWords[1] := A.LongWords[1] shr B;
+ end
+ else
+ begin
+ C := B - 32;
+ A.LongWords[0] := A.LongWords[1] shr C;
+ A.LongWords[1] := 0;
+ end;
+end;
+
+procedure Word64Ror(var A: Word64; const B: Byte);
+var
+ C, D: Byte;
+ E, F: LongWord;
+begin
+ C := B mod 64;
+ if C = 0 then
+ exit;
+ if C < 32 then
+ begin
+ D := 32 - C;
+ E := (A.LongWords[1] shr C) or (A.LongWords[0] shl D);
+ F := (A.LongWords[0] shr C) or (A.LongWords[1] shl D);
+ end
+ else
+ begin
+ Dec(C, 32);
+ D := 32 - C;
+ E := (A.LongWords[0] shr C) or (A.LongWords[1] shl D);
+ F := (A.LongWords[1] shr C) or (A.LongWords[0] shl D);
+ end;
+ A.LongWords[1] := E;
+ A.LongWords[0] := F;
+end;
+
+procedure Word64SwapEndian(var A: Word64);
+var
+ B: Word64;
+ I: Integer;
+begin
+ B := A;
+ for I := 0 to 7 do
+ A.Bytes[I] := B.Bytes[7 - I];
+end;
+
+procedure SwapEndianBuf64(var Buf; const Count: Integer);
+var
+ P: PWord64;
+ I: Integer;
+begin
+ P := @Buf;
+ for I := 1 to Count do
+ begin
+ Word64SwapEndian(P^);
+ Inc(P);
+ end;
+end;
+
+{ }
+{ MD5 hashing }
+{ }
+const
+ MD5Table_1: array [0 .. 15] of LongWord = (
+ $D76AA478, $E8C7B756, $242070DB, $C1BDCEEE,
+ $F57C0FAF, $4787C62A, $A8304613, $FD469501,
+ $698098D8, $8B44F7AF, $FFFF5BB1, $895CD7BE,
+ $6B901122, $FD987193, $A679438E, $49B40821);
+ MD5Table_2: array [0 .. 15] of LongWord = (
+ $F61E2562, $C040B340, $265E5A51, $E9B6C7AA,
+ $D62F105D, $02441453, $D8A1E681, $E7D3FBC8,
+ $21E1CDE6, $C33707D6, $F4D50D87, $455A14ED,
+ $A9E3E905, $FCEFA3F8, $676F02D9, $8D2A4C8A);
+ MD5Table_3: array [0 .. 15] of LongWord = (
+ $FFFA3942, $8771F681, $6D9D6122, $FDE5380C,
+ $A4BEEA44, $4BDECFA9, $F6BB4B60, $BEBFBC70,
+ $289B7EC6, $EAA127FA, $D4EF3085, $04881D05,
+ $D9D4D039, $E6DB99E5, $1FA27CF8, $C4AC5665);
+ MD5Table_4: array [0 .. 15] of LongWord = (
+ $F4292244, $432AFF97, $AB9423A7, $FC93A039,
+ $655B59C3, $8F0CCC92, $FFEFF47D, $85845DD1,
+ $6FA87E4F, $FE2CE6E0, $A3014314, $4E0811A1,
+ $F7537E82, $BD3AF235, $2AD7D2BB, $EB86D391);
+
+{ Calculates a MD5 Digest (16 bytes) given a Buffer (64 bytes) }
+{$IFOPT Q+}{$DEFINE QOn}{$Q-}{$ELSE}{$UNDEF QOn}{$ENDIF}
+
+
+procedure TransformMD5Buffer(var Digest: T128BitDigest; const Buffer);
+var
+ A, B, C, D: LongWord;
+ P : PLongWord;
+ I : Integer;
+ J : Byte;
+ Buf : array [0 .. 15] of LongWord absolute Buffer;
+begin
+ A := Digest.Longs[0];
+ B := Digest.Longs[1];
+ C := Digest.Longs[2];
+ D := Digest.Longs[3];
+
+ P := @MD5Table_1;
+ for I := 0 to 3 do
+ begin
+ J := I * 4;
+ Inc(A, Buf[J] + P^ + (D xor (B and (C xor D))));
+ A := A shl 7 or A shr 25 + B;
+ Inc(P);
+ Inc(D, Buf[J + 1] + P^ + (C xor (A and (B xor C))));
+ D := D shl 12 or D shr 20 + A;
+ Inc(P);
+ Inc(C, Buf[J + 2] + P^ + (B xor (D and (A xor B))));
+ C := C shl 17 or C shr 15 + D;
+ Inc(P);
+ Inc(B, Buf[J + 3] + P^ + (A xor (C and (D xor A))));
+ B := B shl 22 or B shr 10 + C;
+ Inc(P);
+ end;
+
+ P := @MD5Table_2;
+ for I := 0 to 3 do
+ begin
+ J := I * 4;
+ Inc(A, Buf[J + 1] + P^ + (C xor (D and (B xor C))));
+ A := A shl 5 or A shr 27 + B;
+ Inc(P);
+ Inc(D, Buf[(J + 6) mod 16] + P^ + (B xor (C and (A xor B))));
+ D := D shl 9 or D shr 23 + A;
+ Inc(P);
+ Inc(C, Buf[(J + 11) mod 16] + P^ + (A xor (B and (D xor A))));
+ C := C shl 14 or C shr 18 + D;
+ Inc(P);
+ Inc(B, Buf[J] + P^ + (D xor (A and (C xor D))));
+ B := B shl 20 or B shr 12 + C;
+ Inc(P);
+ end;
+
+ P := @MD5Table_3;
+ for I := 0 to 3 do
+ begin
+ J := 16 - (I * 4);
+ Inc(A, Buf[(J + 5) mod 16] + P^ + (B xor C xor D));
+ A := A shl 4 or A shr 28 + B;
+ Inc(P);
+ Inc(D, Buf[(J + 8) mod 16] + P^ + (A xor B xor C));
+ D := D shl 11 or D shr 21 + A;
+ Inc(P);
+ Inc(C, Buf[(J + 11) mod 16] + P^ + (D xor A xor B));
+ C := C shl 16 or C shr 16 + D;
+ Inc(P);
+ Inc(B, Buf[(J + 14) mod 16] + P^ + (C xor D xor A));
+ B := B shl 23 or B shr 9 + C;
+ Inc(P);
+ end;
+
+ P := @MD5Table_4;
+ for I := 0 to 3 do
+ begin
+ J := 16 - (I * 4);
+ Inc(A, Buf[J mod 16] + P^ + (C xor (B or not D)));
+ A := A shl 6 or A shr 26 + B;
+ Inc(P);
+ Inc(D, Buf[(J + 7) mod 16] + P^ + (B xor (A or not C)));
+ D := D shl 10 or D shr 22 + A;
+ Inc(P);
+ Inc(C, Buf[(J + 14) mod 16] + P^ + (A xor (D or not B)));
+ C := C shl 15 or C shr 17 + D;
+ Inc(P);
+ Inc(B, Buf[(J + 5) mod 16] + P^ + (D xor (C or not A)));
+ B := B shl 21 or B shr 11 + C;
+ Inc(P);
+ end;
+
+ Inc(Digest.Longs[0], A);
+ Inc(Digest.Longs[1], B);
+ Inc(Digest.Longs[2], C);
+ Inc(Digest.Longs[3], D);
+end;
+{$IFDEF QOn}{$Q+}{$ENDIF}
+
+
+procedure MD5InitDigest(var Digest: T128BitDigest);
+begin
+ Digest.Longs[0] := $67452301;
+ Digest.Longs[1] := $EFCDAB89;
+ Digest.Longs[2] := $98BADCFE;
+ Digest.Longs[3] := $10325476;
+end;
+
+procedure MD5Buf(var Digest: T128BitDigest; const Buf; const BufSize: Integer);
+var
+ P : PByte;
+ I, J: Integer;
+begin
+ I := BufSize;
+ if I <= 0 then
+ exit;
+ Assert(I mod 64 = 0, 'BufSize must be multiple of 64 bytes');
+ P := @Buf;
+ for J := 0 to I div 64 - 1 do
+ begin
+ TransformMD5Buffer(Digest, P^);
+ Inc(P, 64);
+ end;
+end;
+
+procedure MD5FinalBuf(var Digest: T128BitDigest; const Buf; const BufSize: Integer; const TotalSize: Int64);
+var
+ B1, B2: T512BitBuf;
+ C : Integer;
+begin
+ StdFinalBuf512(Buf, BufSize, TotalSize, B1, B2, C, False);
+ TransformMD5Buffer(Digest, B1);
+ if C > 1 then
+ TransformMD5Buffer(Digest, B2);
+ SecureClear512(B1);
+ if C > 1 then
+ SecureClear512(B2);
+end;
+
+function CalcMD5(const Buf; const BufSize: Integer): T128BitDigest;
+var
+ I, J: Integer;
+ P : PByte;
+begin
+ MD5InitDigest(Result);
+ P := @Buf;
+ if BufSize <= 0 then
+ I := 0
+ else
+ I := BufSize;
+ J := (I div 64) * 64;
+ if J > 0 then
+ begin
+ MD5Buf(Result, P^, J);
+ Inc(P, J);
+ Dec(I, J);
+ end;
+ MD5FinalBuf(Result, P^, I, BufSize);
+end;
+
+function CalcMD5(const Buf: AnsiString): T128BitDigest;
+begin
+ Result := CalcMD5(Pointer(Buf)^, Length(Buf));
+end;
+
+function MD5DigestToStrA(const Digest: T128BitDigest): AnsiString;
+begin
+ SetLength(Result, Sizeof(Digest));
+ Move(Digest, Pointer(Result)^, Sizeof(Digest));
+end;
+
+function MD5DigestToHexA(const Digest: T128BitDigest): AnsiString;
+begin
+ Result := DigestToHexA(Digest, Sizeof(Digest));
+end;
+
+function MD5DigestToHexW(const Digest: T128BitDigest): WideString;
+begin
+ Result := DigestToHexW(Digest, Sizeof(Digest));
+end;
+
+{ }
+{ SHA hashing }
+{ }
+procedure SHA1InitDigest(var Digest: T160BitDigest);
+begin
+ Digest.Longs[0] := $67452301;
+ Digest.Longs[1] := $EFCDAB89;
+ Digest.Longs[2] := $98BADCFE;
+ Digest.Longs[3] := $10325476;
+ Digest.Longs[4] := $C3D2E1F0;
+end;
+
+{ Calculates a SHA Digest (20 bytes) given a Buffer (64 bytes) }
+{$IFOPT Q+}{$DEFINE QOn}{$Q-}{$ELSE}{$UNDEF QOn}{$ENDIF}
+
+
+procedure TransformSHABuffer(var Digest: T160BitDigest; const Buffer; const SHA1: Boolean);
+var
+ A, B, C, D, E: LongWord;
+ W : array [0 .. 79] of LongWord;
+ P, Q : PLongWord;
+ I : Integer;
+ J : LongWord;
+begin
+ P := @Buffer;
+ Q := @W;
+ for I := 0 to 15 do
+ begin
+ Q^ := SwapEndian(P^);
+ Inc(P);
+ Inc(Q);
+ end;
+ for I := 0 to 63 do
+ begin
+ P := Q;
+ Dec(P, 16);
+ J := P^;
+ Inc(P, 2);
+ J := J xor P^;
+ Inc(P, 6);
+ J := J xor P^;
+ Inc(P, 5);
+ J := J xor P^;
+ if SHA1 then
+ J := RotateLeftBits(J, 1);
+ Q^ := J;
+ Inc(Q);
+ end;
+
+ A := Digest.Longs[0];
+ B := Digest.Longs[1];
+ C := Digest.Longs[2];
+ D := Digest.Longs[3];
+ E := Digest.Longs[4];
+
+ P := @W;
+ for I := 0 to 3 do
+ begin
+ Inc(E, (A shl 5 or A shr 27) + (D xor (B and (C xor D))) + P^ + $5A827999);
+ B := B shr 2 or B shl 30;
+ Inc(P);
+ Inc(D, (E shl 5 or E shr 27) + (C xor (A and (B xor C))) + P^ + $5A827999);
+ A := A shr 2 or A shl 30;
+ Inc(P);
+ Inc(C, (D shl 5 or D shr 27) + (B xor (E and (A xor B))) + P^ + $5A827999);
+ E := E shr 2 or E shl 30;
+ Inc(P);
+ Inc(B, (C shl 5 or C shr 27) + (A xor (D and (E xor A))) + P^ + $5A827999);
+ D := D shr 2 or D shl 30;
+ Inc(P);
+ Inc(A, (B shl 5 or B shr 27) + (E xor (C and (D xor E))) + P^ + $5A827999);
+ C := C shr 2 or C shl 30;
+ Inc(P);
+ end;
+
+ for I := 0 to 3 do
+ begin
+ Inc(E, (A shl 5 or A shr 27) + (D xor B xor C) + P^ + $6ED9EBA1);
+ B := B shr 2 or B shl 30;
+ Inc(P);
+ Inc(D, (E shl 5 or E shr 27) + (C xor A xor B) + P^ + $6ED9EBA1);
+ A := A shr 2 or A shl 30;
+ Inc(P);
+ Inc(C, (D shl 5 or D shr 27) + (B xor E xor A) + P^ + $6ED9EBA1);
+ E := E shr 2 or E shl 30;
+ Inc(P);
+ Inc(B, (C shl 5 or C shr 27) + (A xor D xor E) + P^ + $6ED9EBA1);
+ D := D shr 2 or D shl 30;
+ Inc(P);
+ Inc(A, (B shl 5 or B shr 27) + (E xor C xor D) + P^ + $6ED9EBA1);
+ C := C shr 2 or C shl 30;
+ Inc(P);
+ end;
+
+ for I := 0 to 3 do
+ begin
+ Inc(E, (A shl 5 or A shr 27) + ((B and C) or (D and (B or C))) + P^ + $8F1BBCDC);
+ B := B shr 2 or B shl 30;
+ Inc(P);
+ Inc(D, (E shl 5 or E shr 27) + ((A and B) or (C and (A or B))) + P^ + $8F1BBCDC);
+ A := A shr 2 or A shl 30;
+ Inc(P);
+ Inc(C, (D shl 5 or D shr 27) + ((E and A) or (B and (E or A))) + P^ + $8F1BBCDC);
+ E := E shr 2 or E shl 30;
+ Inc(P);
+ Inc(B, (C shl 5 or C shr 27) + ((D and E) or (A and (D or E))) + P^ + $8F1BBCDC);
+ D := D shr 2 or D shl 30;
+ Inc(P);
+ Inc(A, (B shl 5 or B shr 27) + ((C and D) or (E and (C or D))) + P^ + $8F1BBCDC);
+ C := C shr 2 or C shl 30;
+ Inc(P);
+ end;
+
+ for I := 0 to 3 do
+ begin
+ Inc(E, (A shl 5 or A shr 27) + (D xor B xor C) + P^ + $CA62C1D6);
+ B := B shr 2 or B shl 30;
+ Inc(P);
+ Inc(D, (E shl 5 or E shr 27) + (C xor A xor B) + P^ + $CA62C1D6);
+ A := A shr 2 or A shl 30;
+ Inc(P);
+ Inc(C, (D shl 5 or D shr 27) + (B xor E xor A) + P^ + $CA62C1D6);
+ E := E shr 2 or E shl 30;
+ Inc(P);
+ Inc(B, (C shl 5 or C shr 27) + (A xor D xor E) + P^ + $CA62C1D6);
+ D := D shr 2 or D shl 30;
+ Inc(P);
+ Inc(A, (B shl 5 or B shr 27) + (E xor C xor D) + P^ + $CA62C1D6);
+ C := C shr 2 or C shl 30;
+ Inc(P);
+ end;
+
+ Inc(Digest.Longs[0], A);
+ Inc(Digest.Longs[1], B);
+ Inc(Digest.Longs[2], C);
+ Inc(Digest.Longs[3], D);
+ Inc(Digest.Longs[4], E);
+end;
+{$IFDEF QOn}{$Q+}{$ENDIF}
+
+
+procedure SHA1Buf(var Digest: T160BitDigest; const Buf; const BufSize: Integer);
+var
+ P : PByte;
+ I, J: Integer;
+begin
+ I := BufSize;
+ if I <= 0 then
+ exit;
+ Assert(I mod 64 = 0, 'BufSize must be multiple of 64 bytes');
+ P := @Buf;
+ for J := 0 to I div 64 - 1 do
+ begin
+ TransformSHABuffer(Digest, P^, True);
+ Inc(P, 64);
+ end;
+end;
+
+procedure SHA1FinalBuf(var Digest: T160BitDigest; const Buf; const BufSize: Integer; const TotalSize: Int64);
+var
+ B1, B2: T512BitBuf;
+ C : Integer;
+begin
+ StdFinalBuf512(Buf, BufSize, TotalSize, B1, B2, C, True);
+ TransformSHABuffer(Digest, B1, True);
+ if C > 1 then
+ TransformSHABuffer(Digest, B2, True);
+ SwapEndianBuf(Digest, Sizeof(Digest) div Sizeof(LongWord));
+ SecureClear512(B1);
+ if C > 1 then
+ SecureClear512(B2);
+end;
+
+function CalcSHA1(const Buf; const BufSize: Integer): T160BitDigest;
+var
+ I, J: Integer;
+ P : PByte;
+begin
+ SHA1InitDigest(Result);
+ P := @Buf;
+ if BufSize <= 0 then
+ I := 0
+ else
+ I := BufSize;
+ J := (I div 64) * 64;
+ if J > 0 then
+ begin
+ SHA1Buf(Result, P^, J);
+ Inc(P, J);
+ Dec(I, J);
+ end;
+ SHA1FinalBuf(Result, P^, I, BufSize);
+end;
+
+function CalcSHA1(const Buf: AnsiString): T160BitDigest;
+begin
+ Result := CalcSHA1(Pointer(Buf)^, Length(Buf));
+end;
+
+function SHA1DigestToStrA(const Digest: T160BitDigest): AnsiString;
+begin
+ SetLength(Result, Sizeof(Digest));
+ Move(Digest, Pointer(Result)^, Sizeof(Digest));
+end;
+
+function SHA1DigestToHexA(const Digest: T160BitDigest): AnsiString;
+begin
+ Result := DigestToHexA(Digest, Sizeof(Digest));
+end;
+
+function SHA1DigestToHexW(const Digest: T160BitDigest): WideString;
+begin
+ Result := DigestToHexW(Digest, Sizeof(Digest));
+end;
+
+{ }
+{ SHA224 Hashing }
+{ }
+{ SHA-224 is identical to SHA-256, except that: }
+{ - the initial variable values h0 through h7 are different, and }
+{ - the output is constructed by omitting h7 }
+{ }
+procedure SHA224InitDigest(var Digest: T256BitDigest);
+begin
+ // The second 32 bits of the fractional parts of the square roots of the 9th through 16th primes 23..53
+ Digest.Longs[0] := $C1059ED8;
+ Digest.Longs[1] := $367CD507;
+ Digest.Longs[2] := $3070DD17;
+ Digest.Longs[3] := $F70E5939;
+ Digest.Longs[4] := $FFC00B31;
+ Digest.Longs[5] := $68581511;
+ Digest.Longs[6] := $64F98FA7;
+ Digest.Longs[7] := $BEFA4FA4;
+end;
+
+procedure SHA224Buf(var Digest: T256BitDigest; const Buf; const BufSize: Integer);
+begin
+ SHA256Buf(Digest, Buf, BufSize);
+end;
+
+procedure SHA224FinalBuf(var Digest: T256BitDigest; const Buf; const BufSize: Integer; const TotalSize: Int64;
+ var OutDigest: T224BitDigest);
+begin
+ SHA256FinalBuf(Digest, Buf, BufSize, TotalSize);
+ Move(Digest.Longs[0], OutDigest.Longs[0], SizeOf(T224BitDigest));
+end;
+
+function CalcSHA224(const Buf; const BufSize: Integer): T224BitDigest;
+var
+ D : T256BitDigest;
+ I, J: Integer;
+ P : PByte;
+begin
+ SHA224InitDigest(D);
+ P := @Buf;
+ if BufSize <= 0 then
+ I := 0
+ else
+ I := BufSize;
+ J := (I div 64) * 64;
+ if J > 0 then
+ begin
+ SHA224Buf(D, P^, J);
+ Inc(P, J);
+ Dec(I, J);
+ end;
+ SHA224FinalBuf(D, P^, I, BufSize, Result);
+end;
+
+function CalcSHA224(const Buf: AnsiString): T224BitDigest;
+begin
+ Result := CalcSHA224(Pointer(Buf)^, Length(Buf));
+end;
+
+function SHA224DigestToStrA(const Digest: T224BitDigest): AnsiString;
+begin
+ SetLength(Result, Sizeof(Digest));
+ Move(Digest, Pointer(Result)^, Sizeof(Digest));
+end;
+
+function SHA224DigestToHexA(const Digest: T224BitDigest): AnsiString;
+begin
+ Result := DigestToHexA(Digest, Sizeof(Digest));
+end;
+
+function SHA224DigestToHexW(const Digest: T224BitDigest): WideString;
+begin
+ Result := DigestToHexW(Digest, Sizeof(Digest));
+end;
+
+{ }
+{ SHA256 hashing }
+{ }
+procedure SHA256InitDigest(var Digest: T256BitDigest);
+begin
+ Digest.Longs[0] := $6A09E667;
+ Digest.Longs[1] := $BB67AE85;
+ Digest.Longs[2] := $3C6EF372;
+ Digest.Longs[3] := $A54FF53A;
+ Digest.Longs[4] := $510E527F;
+ Digest.Longs[5] := $9B05688C;
+ Digest.Longs[6] := $1F83D9AB;
+ Digest.Longs[7] := $5BE0CD19;
+end;
+
+function SHA256Transform1(const A: LongWord): LongWord;
+begin
+ Result := RotateRightBits(A, 7) xor RotateRightBits(A, 18) xor (A shr 3);
+end;
+
+function SHA256Transform2(const A: LongWord): LongWord;
+begin
+ Result := RotateRightBits(A, 17) xor RotateRightBits(A, 19) xor (A shr 10);
+end;
+
+function SHA256Transform3(const A: LongWord): LongWord;
+begin
+ Result := RotateRightBits(A, 2) xor RotateRightBits(A, 13) xor RotateRightBits(A, 22);
+end;
+
+function SHA256Transform4(const A: LongWord): LongWord;
+begin
+ Result := RotateRightBits(A, 6) xor RotateRightBits(A, 11) xor RotateRightBits(A, 25);
+end;
+
+const
+ // first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311
+ SHA256K: array [0 .. 63] of LongWord = (
+ $428A2F98, $71374491, $B5C0FBCF, $E9B5DBA5, $3956C25B, $59F111F1, $923F82A4, $AB1C5ED5,
+ $D807AA98, $12835B01, $243185BE, $550C7DC3, $72BE5D74, $80DEB1FE, $9BDC06A7, $C19BF174,
+ $E49B69C1, $EFBE4786, $0FC19DC6, $240CA1CC, $2DE92C6F, $4A7484AA, $5CB0A9DC, $76F988DA,
+ $983E5152, $A831C66D, $B00327C8, $BF597FC7, $C6E00BF3, $D5A79147, $06CA6351, $14292967,
+ $27B70A85, $2E1B2138, $4D2C6DFC, $53380D13, $650A7354, $766A0ABB, $81C2C92E, $92722C85,
+ $A2BFE8A1, $A81A664B, $C24B8B70, $C76C51A3, $D192E819, $D6990624, $F40E3585, $106AA070,
+ $19A4C116, $1E376C08, $2748774C, $34B0BCB5, $391C0CB3, $4ED8AA4A, $5B9CCA4F, $682E6FF3,
+ $748F82EE, $78A5636F, $84C87814, $8CC70208, $90BEFFFA, $A4506CEB, $BEF9A3F7, $C67178F2
+ );
+
+{$IFOPT Q+}{$DEFINE QOn}{$Q-}{$ELSE}{$UNDEF QOn}{$ENDIF}
+
+
+procedure TransformSHA256Buffer(var Digest: T256BitDigest; const Buf);
+var
+ I : Integer;
+ W : array [0 .. 63] of LongWord;
+ P : PLongWord;
+ S0, S1, Maj, T1, T2, Ch: LongWord;
+ H : array [0 .. 7] of LongWord;
+begin
+ P := @Buf;
+ for I := 0 to 15 do
+ begin
+ W[I] := SwapEndian(P^);
+ Inc(P);
+ end;
+ for I := 16 to 63 do
+ begin
+ S0 := SHA256Transform1(W[I - 15]);
+ S1 := SHA256Transform2(W[I - 2]);
+ W[I] := W[I - 16] + S0 + W[I - 7] + S1;
+ end;
+ for I := 0 to 7 do
+ H[I] := Digest.Longs[I];
+ for I := 0 to 63 do
+ begin
+ S0 := SHA256Transform3(H[0]);
+ Maj := (H[0] and H[1]) xor (H[0] and H[2]) xor (H[1] and H[2]);
+ T2 := S0 + Maj;
+ S1 := SHA256Transform4(H[4]);
+ Ch := (H[4] and H[5]) xor ((not H[4]) and H[6]);
+ T1 := H[7] + S1 + Ch + SHA256K[I] + W[I];
+ H[7] := H[6];
+ H[6] := H[5];
+ H[5] := H[4];
+ H[4] := H[3] + T1;
+ H[3] := H[2];
+ H[2] := H[1];
+ H[1] := H[0];
+ H[0] := T1 + T2;
+ end;
+ for I := 0 to 7 do
+ Inc(Digest.Longs[I], H[I]);
+end;
+{$IFDEF QOn}{$Q+}{$ENDIF}
+
+
+procedure SHA256Buf(var Digest: T256BitDigest; const Buf; const BufSize: Integer);
+var
+ P : PByte;
+ I, J: Integer;
+begin
+ I := BufSize;
+ if I <= 0 then
+ exit;
+ Assert(I mod 64 = 0, 'BufSize must be multiple of 64 bytes');
+ P := @Buf;
+ for J := 0 to I div 64 - 1 do
+ begin
+ TransformSHA256Buffer(Digest, P^);
+ Inc(P, 64);
+ end;
+end;
+
+procedure SHA256FinalBuf(var Digest: T256BitDigest; const Buf; const BufSize: Integer; const TotalSize: Int64);
+var
+ B1, B2: T512BitBuf;
+ C : Integer;
+begin
+ StdFinalBuf512(Buf, BufSize, TotalSize, B1, B2, C, True);
+ TransformSHA256Buffer(Digest, B1);
+ if C > 1 then
+ TransformSHA256Buffer(Digest, B2);
+ SwapEndianBuf(Digest, Sizeof(Digest) div Sizeof(LongWord));
+ SecureClear512(B1);
+ if C > 1 then
+ SecureClear512(B2);
+end;
+
+function CalcSHA256(const Buf; const BufSize: Integer): T256BitDigest;
+var
+ I, J: Integer;
+ P : PByte;
+begin
+ SHA256InitDigest(Result);
+ P := @Buf;
+ if BufSize <= 0 then
+ I := 0
+ else
+ I := BufSize;
+ J := (I div 64) * 64;
+ if J > 0 then
+ begin
+ SHA256Buf(Result, P^, J);
+ Inc(P, J);
+ Dec(I, J);
+ end;
+ SHA256FinalBuf(Result, P^, I, BufSize);
+end;
+
+function CalcSHA256(const Buf: AnsiString): T256BitDigest;
+begin
+ Result := CalcSHA256(Pointer(Buf)^, Length(Buf));
+end;
+
+function SHA256DigestToStrA(const Digest: T256BitDigest): AnsiString;
+begin
+ SetLength(Result, Sizeof(Digest));
+ Move(Digest, Pointer(Result)^, Sizeof(Digest));
+end;
+
+function SHA256DigestToHexA(const Digest: T256BitDigest): AnsiString;
+begin
+ Result := DigestToHexA(Digest, Sizeof(Digest));
+end;
+
+function SHA256DigestToHexW(const Digest: T256BitDigest): WideString;
+begin
+ Result := DigestToHexW(Digest, Sizeof(Digest));
+end;
+
+{ }
+{ SHA384 Hashing }
+{ }
+procedure SHA384InitDigest(var Digest: T512BitDigest);
+begin
+ Digest.Word64s[0].LongWords[0] := $C1059ED8;
+ Digest.Word64s[0].LongWords[1] := $CBBB9D5D;
+ Digest.Word64s[1].LongWords[0] := $367CD507;
+ Digest.Word64s[1].LongWords[1] := $629A292A;
+ Digest.Word64s[2].LongWords[0] := $3070DD17;
+ Digest.Word64s[2].LongWords[1] := $9159015A;
+ Digest.Word64s[3].LongWords[0] := $F70E5939;
+ Digest.Word64s[3].LongWords[1] := $152FECD8;
+ Digest.Word64s[4].LongWords[0] := $FFC00B31;
+ Digest.Word64s[4].LongWords[1] := $67332667;
+ Digest.Word64s[5].LongWords[0] := $68581511;
+ Digest.Word64s[5].LongWords[1] := $8EB44A87;
+ Digest.Word64s[6].LongWords[0] := $64F98FA7;
+ Digest.Word64s[6].LongWords[1] := $DB0C2E0D;
+ Digest.Word64s[7].LongWords[0] := $BEFA4FA4;
+ Digest.Word64s[7].LongWords[1] := $47B5481D;
+end;
+
+procedure SHA384Buf(var Digest: T512BitDigest; const Buf; const BufSize: Integer);
+begin
+ SHA512Buf(Digest, Buf, BufSize);
+end;
+
+procedure SHA384FinalBuf(var Digest: T512BitDigest; const Buf; const BufSize: Integer; const TotalSize: Int64; var OutDigest: T384BitDigest);
+begin
+ SHA512FinalBuf(Digest, Buf, BufSize, TotalSize);
+ Move(Digest, OutDigest, SizeOf(OutDigest));
+end;
+
+function CalcSHA384(const Buf; const BufSize: Integer): T384BitDigest;
+var
+ I, J: Integer;
+ P : PByte;
+ D : T512BitDigest;
+begin
+ SHA384InitDigest(D);
+ P := @Buf;
+ if BufSize <= 0 then
+ I := 0
+ else
+ I := BufSize;
+ J := (I div 128) * 128;
+ if J > 0 then
+ begin
+ SHA384Buf(D, P^, J);
+ Inc(P, J);
+ Dec(I, J);
+ end;
+ SHA384FinalBuf(D, P^, I, BufSize, Result);
+end;
+
+function CalcSHA384(const Buf: AnsiString): T384BitDigest;
+begin
+ Result := CalcSHA384(Pointer(Buf)^, Length(Buf));
+end;
+
+function SHA384DigestToStrA(const Digest: T384BitDigest): AnsiString;
+begin
+ SetLength(Result, Sizeof(Digest));
+ Move(Digest, Pointer(Result)^, Sizeof(Digest));
+end;
+
+function SHA384DigestToHexA(const Digest: T384BitDigest): AnsiString;
+begin
+ Result := DigestToHexA(Digest, Sizeof(Digest));
+end;
+
+function SHA384DigestToHexW(const Digest: T384BitDigest): WideString;
+begin
+ Result := DigestToHexW(Digest, Sizeof(Digest));
+end;
+
+{ }
+{ SHA512 Hashing }
+{ }
+procedure SHA512InitDigest(var Digest: T512BitDigest);
+begin
+ Digest.Word64s[0].LongWords[0] := $F3BCC908;
+ Digest.Word64s[0].LongWords[1] := $6A09E667;
+ Digest.Word64s[1].LongWords[0] := $84CAA73B;
+ Digest.Word64s[1].LongWords[1] := $BB67AE85;
+ Digest.Word64s[2].LongWords[0] := $FE94F82B;
+ Digest.Word64s[2].LongWords[1] := $3C6EF372;
+ Digest.Word64s[3].LongWords[0] := $5F1D36F1;
+ Digest.Word64s[3].LongWords[1] := $A54FF53A;
+ Digest.Word64s[4].LongWords[0] := $ADE682D1;
+ Digest.Word64s[4].LongWords[1] := $510E527F;
+ Digest.Word64s[5].LongWords[0] := $2B3E6C1F;
+ Digest.Word64s[5].LongWords[1] := $9B05688C;
+ Digest.Word64s[6].LongWords[0] := $FB41BD6B;
+ Digest.Word64s[6].LongWords[1] := $1F83D9AB;
+ Digest.Word64s[7].LongWords[0] := $137E2179;
+ Digest.Word64s[7].LongWords[1] := $5BE0CD19;
+end;
+
+// BSIG0(x) = ROTR^28(x) XOR ROTR^34(x) XOR ROTR^39(x)
+function SHA512Transform1(const A: Word64): Word64;
+var
+ T1, T2, T3: Word64;
+begin
+ T1 := A;
+ T2 := A;
+ T3 := A;
+ Word64Ror(T1, 28);
+ Word64Ror(T2, 34);
+ Word64Ror(T3, 39);
+ Word64XorWord64(T1, T2);
+ Word64XorWord64(T1, T3);
+ Result := T1;
+end;
+
+// BSIG1(x) = ROTR^14(x) XOR ROTR^18(x) XOR ROTR^41(x)
+function SHA512Transform2(const A: Word64): Word64;
+var
+ T1, T2, T3: Word64;
+begin
+ T1 := A;
+ T2 := A;
+ T3 := A;
+ Word64Ror(T1, 14);
+ Word64Ror(T2, 18);
+ Word64Ror(T3, 41);
+ Word64XorWord64(T1, T2);
+ Word64XorWord64(T1, T3);
+ Result := T1;
+end;
+
+// SSIG0(x) = ROTR^1(x) XOR ROTR^8(x) XOR SHR^7(x)
+function SHA512Transform3(const A: Word64): Word64;
+var
+ T1, T2, T3: Word64;
+begin
+ T1 := A;
+ T2 := A;
+ T3 := A;
+ Word64Ror(T1, 1);
+ Word64Ror(T2, 8);
+ Word64Shr(T3, 7);
+ Word64XorWord64(T1, T2);
+ Word64XorWord64(T1, T3);
+ Result := T1;
+end;
+
+// SSIG1(x) = ROTR^19(x) XOR ROTR^61(x) XOR SHR^6(x)
+function SHA512Transform4(const A: Word64): Word64;
+var
+ T1, T2, T3: Word64;
+begin
+ T1 := A;
+ T2 := A;
+ T3 := A;
+ Word64Ror(T1, 19);
+ Word64Ror(T2, 61);
+ Word64Shr(T3, 6);
+ Word64XorWord64(T1, T2);
+ Word64XorWord64(T1, T3);
+ Result := T1;
+end;
+
+// CH( x, y, z) = (x AND y) XOR ( (NOT x) AND z)
+function SHA512Transform5(const X, Y, Z: Word64): Word64;
+var
+ T1, T2: Word64;
+begin
+ T1 := X;
+ Word64AndWord64(T1, Y);
+ T2 := X;
+ Word64Not(T2);
+ Word64AndWord64(T2, Z);
+ Word64XorWord64(T1, T2);
+ Result := T1;
+end;
+
+// MAJ( x, y, z) = (x AND y) XOR (x AND z) XOR (y AND z)
+function SHA512Transform6(const X, Y, Z: Word64): Word64;
+var
+ T1, T2, T3: Word64;
+begin
+ T1 := X;
+ Word64AndWord64(T1, Y);
+ T2 := X;
+ Word64AndWord64(T2, Z);
+ T3 := Y;
+ Word64AndWord64(T3, Z);
+ Word64XorWord64(T1, T2);
+ Word64XorWord64(T1, T3);
+ Result := T1;
+end;
+
+const
+ // first 64 bits of the fractional parts of the cube roots of the first eighty prime numbers
+ // (stored High LongWord first then Low LongWord)
+ SHA512K: array [0 .. 159] of LongWord = (
+ $428A2F98, $D728AE22, $71374491, $23EF65CD, $B5C0FBCF, $EC4D3B2F, $E9B5DBA5, $8189DBBC,
+ $3956C25B, $F348B538, $59F111F1, $B605D019, $923F82A4, $AF194F9B, $AB1C5ED5, $DA6D8118,
+ $D807AA98, $A3030242, $12835B01, $45706FBE, $243185BE, $4EE4B28C, $550C7DC3, $D5FFB4E2,
+ $72BE5D74, $F27B896F, $80DEB1FE, $3B1696B1, $9BDC06A7, $25C71235, $C19BF174, $CF692694,
+ $E49B69C1, $9EF14AD2, $EFBE4786, $384F25E3, $0FC19DC6, $8B8CD5B5, $240CA1CC, $77AC9C65,
+ $2DE92C6F, $592B0275, $4A7484AA, $6EA6E483, $5CB0A9DC, $BD41FBD4, $76F988DA, $831153B5,
+ $983E5152, $EE66DFAB, $A831C66D, $2DB43210, $B00327C8, $98FB213F, $BF597FC7, $BEEF0EE4,
+ $C6E00BF3, $3DA88FC2, $D5A79147, $930AA725, $06CA6351, $E003826F, $14292967, $0A0E6E70,
+ $27B70A85, $46D22FFC, $2E1B2138, $5C26C926, $4D2C6DFC, $5AC42AED, $53380D13, $9D95B3DF,
+ $650A7354, $8BAF63DE, $766A0ABB, $3C77B2A8, $81C2C92E, $47EDAEE6, $92722C85, $1482353B,
+ $A2BFE8A1, $4CF10364, $A81A664B, $BC423001, $C24B8B70, $D0F89791, $C76C51A3, $0654BE30,
+ $D192E819, $D6EF5218, $D6990624, $5565A910, $F40E3585, $5771202A, $106AA070, $32BBD1B8,
+ $19A4C116, $B8D2D0C8, $1E376C08, $5141AB53, $2748774C, $DF8EEB99, $34B0BCB5, $E19B48A8,
+ $391C0CB3, $C5C95A63, $4ED8AA4A, $E3418ACB, $5B9CCA4F, $7763E373, $682E6FF3, $D6B2B8A3,
+ $748F82EE, $5DEFB2FC, $78A5636F, $43172F60, $84C87814, $A1F0AB72, $8CC70208, $1A6439EC,
+ $90BEFFFA, $23631E28, $A4506CEB, $DE82BDE9, $BEF9A3F7, $B2C67915, $C67178F2, $E372532B,
+ $CA273ECE, $EA26619C, $D186B8C7, $21C0C207, $EADA7DD6, $CDE0EB1E, $F57D4F7F, $EE6ED178,
+ $06F067AA, $72176FBA, $0A637DC5, $A2C898A6, $113F9804, $BEF90DAE, $1B710B35, $131C471B,
+ $28DB77F5, $23047D84, $32CAAB7B, $40C72493, $3C9EBE0A, $15C9BEBC, $431D67C4, $9C100D4C,
+ $4CC5D4BE, $CB3E42B6, $597F299C, $FC657E2A, $5FCB6FAB, $3AD6FAEC, $6C44198C, $4A475817
+ );
+
+{$IFOPT Q+}{$DEFINE QOn}{$Q-}{$ELSE}{$UNDEF QOn}{$ENDIF}
+
+
+procedure TransformSHA512Buffer(var Digest: T512BitDigest; const Buf);
+var
+ I : Integer;
+ P : PWord64;
+ W : array [0 .. 79] of Word64;
+ T1, T2, T3, T4, K: Word64;
+ H : array [0 .. 7] of Word64;
+begin
+ P := @Buf;
+ for I := 0 to 15 do
+ begin
+ W[I] := P^;
+ Word64SwapEndian(W[I]);
+ Inc(P);
+ end;
+ for I := 16 to 79 do
+ begin
+ T1 := SHA512Transform4(W[I - 2]);
+ T2 := W[I - 7];
+ T3 := SHA512Transform3(W[I - 15]); // bug in RFC (specifies I-5 instead of W[I-5])
+ T4 := W[I - 16];
+ Word64AddWord64(T1, T2);
+ Word64AddWord64(T1, T3);
+ Word64AddWord64(T1, T4);
+ W[I] := T1;
+ end;
+ for I := 0 to 7 do
+ H[I] := Digest.Word64s[I];
+ for I := 0 to 79 do
+ begin
+ // T1 = h + BSIG1(e) + CH(e,f,g) + Kt + Wt
+ T1 := H[7];
+ Word64AddWord64(T1, SHA512Transform2(H[4]));
+ Word64AddWord64(T1, SHA512Transform5(H[4], H[5], H[6]));
+ K.LongWords[0] := SHA512K[I * 2 + 1];
+ K.LongWords[1] := SHA512K[I * 2];
+ Word64AddWord64(T1, K);
+ Word64AddWord64(T1, W[I]);
+ // T2 = BSIG0(a) + MAJ(a,b,c)
+ T2 := SHA512Transform1(H[0]);
+ Word64AddWord64(T2, SHA512Transform6(H[0], H[1], H[2]));
+ // h = g g = f
+ // f = e e = d + T1
+ // d = c c = b
+ // b = a a = T1 + T2
+ H[7] := H[6];
+ H[6] := H[5];
+ H[5] := H[4];
+ H[4] := H[3];
+ Word64AddWord64(H[4], T1);
+ H[3] := H[2];
+ H[2] := H[1];
+ H[1] := H[0];
+ H[0] := T1;
+ Word64AddWord64(H[0], T2);
+ end;
+ for I := 0 to 7 do
+ Word64AddWord64(Digest.Word64s[I], H[I]);
+end;
+{$IFDEF QOn}{$Q+}{$ENDIF}
+
+
+procedure SHA512Buf(var Digest: T512BitDigest; const Buf; const BufSize: Integer);
+var
+ P : PByte;
+ I, J: Integer;
+begin
+ I := BufSize;
+ if I <= 0 then
+ exit;
+ Assert(I mod 128 = 0, 'BufSize must be multiple of 128 bytes');
+ P := @Buf;
+ for J := 0 to I div 128 - 1 do
+ begin
+ TransformSHA512Buffer(Digest, P^);
+ Inc(P, 128);
+ end;
+end;
+
+procedure SHA512FinalBuf(var Digest: T512BitDigest; const Buf; const BufSize: Integer; const TotalSize: Int64);
+var
+ B1, B2: T1024BitBuf;
+ C : Integer;
+begin
+ StdFinalBuf1024(Buf, BufSize, TotalSize, B1, B2, C, True);
+ TransformSHA512Buffer(Digest, B1);
+ if C > 1 then
+ TransformSHA512Buffer(Digest, B2);
+ SwapEndianBuf64(Digest, Sizeof(Digest) div Sizeof(Word64));
+ SecureClear1024(B1);
+ if C > 1 then
+ SecureClear1024(B2);
+end;
+
+function CalcSHA512(const Buf; const BufSize: Integer): T512BitDigest;
+var
+ I, J: Integer;
+ P : PByte;
+begin
+ SHA512InitDigest(Result);
+ P := @Buf;
+ if BufSize <= 0 then
+ I := 0
+ else
+ I := BufSize;
+ J := (I div 128) * 128;
+ if J > 0 then
+ begin
+ SHA512Buf(Result, P^, J);
+ Inc(P, J);
+ Dec(I, J);
+ end;
+ SHA512FinalBuf(Result, P^, I, BufSize);
+end;
+
+function CalcSHA512(const Buf: AnsiString): T512BitDigest;
+begin
+ Result := CalcSHA512(Pointer(Buf)^, Length(Buf));
+end;
+
+function SHA512DigestToStrA(const Digest: T512BitDigest): AnsiString;
+begin
+ SetLength(Result, Sizeof(Digest));
+ Move(Digest, Pointer(Result)^, Sizeof(Digest));
+end;
+
+function SHA512DigestToHexA(const Digest: T512BitDigest): AnsiString;
+begin
+ Result := DigestToHexA(Digest, Sizeof(Digest));
+end;
+
+function SHA512DigestToHexW(const Digest: T512BitDigest): WideString;
+begin
+ Result := DigestToHexW(Digest, Sizeof(Digest));
+end;
+
+{ }
+{ HMAC utility functions }
+{ }
+procedure HMAC_KeyBlock512(const Key; const KeySize: Integer; var Buf: T512BitBuf);
+var
+ P: PAnsiChar;
+begin
+ Assert(KeySize <= 64);
+ P := @Buf;
+ if KeySize > 0 then
+ begin
+ Move(Key, P^, KeySize);
+ Inc(P, KeySize);
+ end;
+ FillChar(P^, 64 - KeySize, #0);
+end;
+
+procedure HMAC_KeyBlock1024(const Key; const KeySize: Integer; var Buf: T1024BitBuf);
+var
+ P: PAnsiChar;
+begin
+ Assert(KeySize <= 128);
+ P := @Buf;
+ if KeySize > 0 then
+ begin
+ Move(Key, P^, KeySize);
+ Inc(P, KeySize);
+ end;
+ FillChar(P^, 128 - KeySize, #0);
+end;
+
+procedure XORBlock512(var Buf: T512BitBuf; const XOR8: Byte);
+var
+ I: Integer;
+begin
+ for I := 0 to SizeOf(Buf) - 1 do
+ Buf[I] := Buf[I] xor XOR8;
+end;
+
+procedure XORBlock1024(var Buf: T1024BitBuf; const XOR8: Byte);
+var
+ I: Integer;
+begin
+ for I := 0 to SizeOf(Buf) - 1 do
+ Buf[I] := Buf[I] xor XOR8;
+end;
+
+{ }
+{ HMAC-MD5 keyed hashing }
+{ }
+procedure HMAC_MD5Init(const Key: Pointer; const KeySize: Integer; var Digest: T128BitDigest; var K: T512BitBuf);
+var
+ S: T512BitBuf;
+ D: T128BitDigest;
+begin
+ MD5InitDigest(Digest);
+
+ if KeySize > 64 then
+ begin
+ D := CalcMD5(Key^, KeySize);
+ HMAC_KeyBlock512(D, Sizeof(D), K);
+ end
+ else
+ HMAC_KeyBlock512(Key^, KeySize, K);
+
+ Move(K, S, SizeOf(K));
+ XORBlock512(S, $36);
+ TransformMD5Buffer(Digest, S);
+ SecureClear512(S);
+end;
+
+procedure HMAC_MD5Buf(var Digest: T128BitDigest; const Buf; const BufSize: Integer);
+begin
+ MD5Buf(Digest, Buf, BufSize);
+end;
+
+procedure HMAC_MD5FinalBuf(const K: T512BitBuf; var Digest: T128BitDigest; const Buf; const BufSize: Integer; const TotalSize: Int64);
+var
+ FinBuf: packed record
+ K : T512BitBuf;
+ D : T128BitDigest;
+end;
+begin
+ MD5FinalBuf(Digest, Buf, BufSize, TotalSize + 64);
+ Move(K, FinBuf.K, SizeOf(K));
+ XORBlock512(FinBuf.K, $5C);
+ Move(Digest, FinBuf.D, SizeOf(Digest));
+ Digest := CalcMD5(FinBuf, SizeOf(FinBuf));
+ SecureClear(FinBuf, SizeOf(FinBuf));
+end;
+
+function CalcHMAC_MD5(const Key: Pointer; const KeySize: Integer; const Buf; const BufSize: Integer): T128BitDigest;
+var
+ I, J: Integer;
+ P : PByte;
+ K : T512BitBuf;
+begin
+ HMAC_MD5Init(Key, KeySize, Result, K);
+ P := @Buf;
+ if BufSize <= 0 then
+ I := 0
+ else
+ I := BufSize;
+ J := (I div 64) * 64;
+ if J > 0 then
+ begin
+ HMAC_MD5Buf(Result, P^, J);
+ Inc(P, J);
+ Dec(I, J);
+ end;
+ HMAC_MD5FinalBuf(K, Result, P^, I, BufSize);
+ SecureClear512(K);
+end;
+
+function CalcHMAC_MD5(const Key: AnsiString; const Buf; const BufSize: Integer): T128BitDigest;
+begin
+ Result := CalcHMAC_MD5(Pointer(Key), Length(Key), Buf, BufSize);
+end;
+
+function CalcHMAC_MD5(const Key, Buf: AnsiString): T128BitDigest;
+begin
+ Result := CalcHMAC_MD5(Key, Pointer(Buf)^, Length(Buf));
+end;
+
+{ }
+{ HMAC-SHA1 keyed hashing }
+{ }
+procedure HMAC_SHA1Init(const Key: Pointer; const KeySize: Integer; var Digest: T160BitDigest; var K: T512BitBuf);
+var
+ D: T160BitDigest;
+ S: T512BitBuf;
+begin
+ SHA1InitDigest(Digest);
+
+ if KeySize > 64 then
+ begin
+ D := CalcSHA1(Key^, KeySize);
+ HMAC_KeyBlock512(D, Sizeof(D), K);
+ end
+ else
+ HMAC_KeyBlock512(Key^, KeySize, K);
+
+ Move(K, S, SizeOf(K));
+ XORBlock512(S, $36);
+ TransformSHABuffer(Digest, S, True);
+ SecureClear512(S);
+end;
+
+procedure HMAC_SHA1Buf(var Digest: T160BitDigest; const Buf; const BufSize: Integer);
+begin
+ SHA1Buf(Digest, Buf, BufSize);
+end;
+
+procedure HMAC_SHA1FinalBuf(const K: T512BitBuf; var Digest: T160BitDigest; const Buf; const BufSize: Integer; const TotalSize: Int64);
+var
+ FinBuf: packed record
+ K : T512BitBuf;
+ D : T160BitDigest;
+end;
+begin
+ SHA1FinalBuf(Digest, Buf, BufSize, TotalSize + 64);
+ Move(K, FinBuf.K, SizeOf(K));
+ XORBlock512(FinBuf.K, $5C);
+ Move(Digest, FinBuf.D, SizeOf(Digest));
+ Digest := CalcSHA1(FinBuf, SizeOf(FinBuf));
+ SecureClear(FinBuf, SizeOf(FinBuf));
+end;
+
+function CalcHMAC_SHA1(const Key: Pointer; const KeySize: Integer; const Buf; const BufSize: Integer): T160BitDigest;
+var
+ I, J: Integer;
+ P : PByte;
+ K : T512BitBuf;
+begin
+ HMAC_SHA1Init(Key, KeySize, Result, K);
+ P := @Buf;
+ if BufSize <= 0 then
+ I := 0
+ else
+ I := BufSize;
+ J := (I div 64) * 64;
+ if J > 0 then
+ begin
+ HMAC_SHA1Buf(Result, P^, J);
+ Inc(P, J);
+ Dec(I, J);
+ end;
+ HMAC_SHA1FinalBuf(K, Result, P^, I, BufSize);
+ SecureClear512(K);
+end;
+
+function CalcHMAC_SHA1(const Key: AnsiString; const Buf; const BufSize: Integer): T160BitDigest;
+begin
+ Result := CalcHMAC_SHA1(Pointer(Key), Length(Key), Buf, BufSize);
+end;
+
+function CalcHMAC_SHA1(const Key, Buf: AnsiString): T160BitDigest;
+begin
+ Result := CalcHMAC_SHA1(Key, Pointer(Buf)^, Length(Buf));
+end;
+
+{ }
+{ HMAC-SHA256 keyed hashing }
+{ }
+procedure HMAC_SHA256Init(const Key: Pointer; const KeySize: Integer; var Digest: T256BitDigest; var K: T512BitBuf);
+var
+ D: T256BitDigest;
+ S: T512BitBuf;
+begin
+ SHA256InitDigest(Digest);
+
+ if KeySize > 64 then
+ begin
+ D := CalcSHA256(Key^, KeySize);
+ HMAC_KeyBlock512(D, Sizeof(D), K);
+ end
+ else
+ HMAC_KeyBlock512(Key^, KeySize, K);
+
+ Move(K, S, SizeOf(K));
+ XORBlock512(S, $36);
+ TransformSHA256Buffer(Digest, S);
+ SecureClear512(S);
+end;
+
+procedure HMAC_SHA256Buf(var Digest: T256BitDigest; const Buf; const BufSize: Integer);
+begin
+ SHA256Buf(Digest, Buf, BufSize);
+end;
+
+procedure HMAC_SHA256FinalBuf(const K: T512BitBuf; var Digest: T256BitDigest; const Buf; const BufSize: Integer; const TotalSize: Int64);
+var
+ FinBuf: packed record
+ K : T512BitBuf;
+ D : T256BitDigest;
+end;
+begin
+ SHA256FinalBuf(Digest, Buf, BufSize, TotalSize + 64);
+ Move(K, FinBuf.K, SizeOf(K));
+ XORBlock512(FinBuf.K, $5C);
+ Move(Digest, FinBuf.D, SizeOf(Digest));
+ Digest := CalcSHA256(FinBuf, SizeOf(FinBuf));
+ SecureClear(FinBuf, SizeOf(FinBuf));
+end;
+
+function CalcHMAC_SHA256(const Key: Pointer; const KeySize: Integer; const Buf; const BufSize: Integer): T256BitDigest;
+var
+ I, J: Integer;
+ P : PByte;
+ K : T512BitBuf;
+begin
+ HMAC_SHA256Init(Key, KeySize, Result, K);
+ P := @Buf;
+ if BufSize <= 0 then
+ I := 0
+ else
+ I := BufSize;
+ J := (I div 64) * 64;
+ if J > 0 then
+ begin
+ HMAC_SHA256Buf(Result, P^, J);
+ Inc(P, J);
+ Dec(I, J);
+ end;
+ HMAC_SHA256FinalBuf(K, Result, P^, I, BufSize);
+ SecureClear512(K);
+end;
+
+function CalcHMAC_SHA256(const Key: AnsiString; const Buf; const BufSize: Integer): T256BitDigest;
+begin
+ Result := CalcHMAC_SHA256(Pointer(Key), Length(Key), Buf, BufSize);
+end;
+
+function CalcHMAC_SHA256(const Key, Buf: AnsiString): T256BitDigest;
+begin
+ Result := CalcHMAC_SHA256(Key, Pointer(Buf)^, Length(Buf));
+end;
+
+{ }
+{ HMAC-SHA512 keyed hashing }
+{ }
+procedure HMAC_SHA512Init(const Key: Pointer; const KeySize: Integer; var Digest: T512BitDigest; var K: T1024BitBuf);
+var
+ D: T512BitDigest;
+ S: T1024BitBuf;
+begin
+ SHA512InitDigest(Digest);
+
+ if KeySize > 128 then
+ begin
+ D := CalcSHA512(Key^, KeySize);
+ HMAC_KeyBlock1024(D, Sizeof(D), K);
+ end
+ else
+ HMAC_KeyBlock1024(Key^, KeySize, K);
+
+ Move(K, S, SizeOf(K));
+ XORBlock1024(S, $36);
+ TransformSHA512Buffer(Digest, S);
+ SecureClear1024(S);
+end;
+
+procedure HMAC_SHA512Buf(var Digest: T512BitDigest; const Buf; const BufSize: Integer);
+begin
+ SHA512Buf(Digest, Buf, BufSize);
+end;
+
+procedure HMAC_SHA512FinalBuf(const K: T1024BitBuf; var Digest: T512BitDigest; const Buf; const BufSize: Integer; const TotalSize: Int64);
+var
+ FinBuf: packed record
+ K : T1024BitBuf;
+ D : T512BitDigest;
+end;
+begin
+ SHA512FinalBuf(Digest, Buf, BufSize, TotalSize + 128);
+ Move(K, FinBuf.K, SizeOf(K));
+ XORBlock1024(FinBuf.K, $5C);
+ Move(Digest, FinBuf.D, SizeOf(Digest));
+ Digest := CalcSHA512(FinBuf, SizeOf(FinBuf));
+ SecureClear(FinBuf, SizeOf(FinBuf));
+end;
+
+function CalcHMAC_SHA512(const Key: Pointer; const KeySize: Integer; const Buf; const BufSize: Integer): T512BitDigest;
+var
+ I, J: Integer;
+ P : PByte;
+ K : T1024BitBuf;
+begin
+ HMAC_SHA512Init(Key, KeySize, Result, K);
+ P := @Buf;
+ if BufSize <= 0 then
+ I := 0
+ else
+ I := BufSize;
+ J := (I div 128) * 128;
+ if J > 0 then
+ begin
+ HMAC_SHA512Buf(Result, P^, J);
+ Inc(P, J);
+ Dec(I, J);
+ end;
+ HMAC_SHA512FinalBuf(K, Result, P^, I, BufSize);
+ SecureClear1024(K);
+end;
+
+function CalcHMAC_SHA512(const Key: AnsiString; const Buf; const BufSize: Integer): T512BitDigest;
+begin
+ Result := CalcHMAC_SHA512(Pointer(Key), Length(Key), Buf, BufSize);
+end;
+
+function CalcHMAC_SHA512(const Key, Buf: AnsiString): T512BitDigest;
+begin
+ Result := CalcHMAC_SHA512(Key, Pointer(Buf)^, Length(Buf));
+end;
+
+{ }
+{ CalculateHash }
+{ }
+procedure CalculateHash(const HashType: THashType;
+ const Buf; const BufSize: Integer;
+ const Digest: Pointer;
+ const Key: Pointer; const KeySize: Integer);
+begin
+ if KeySize > 0 then
+ case HashType of
+ hashHMAC_MD5:
+ P128BitDigest(Digest)^ := CalcHMAC_MD5(Key, KeySize, Buf, BufSize);
+ hashHMAC_SHA1:
+ P160BitDigest(Digest)^ := CalcHMAC_SHA1(Key, KeySize, Buf, BufSize);
+ hashHMAC_SHA256:
+ P256BitDigest(Digest)^ := CalcHMAC_SHA256(Key, KeySize, Buf, BufSize);
+ hashHMAC_SHA512:
+ P512BitDigest(Digest)^ := CalcHMAC_SHA512(Key, KeySize, Buf, BufSize);
+ else
+ raise EHashError.Create(hashNotKeyedHashType);
+ end
+ else
+ case HashType of
+ hashChecksum32:
+ PLongWord(Digest)^ := CalcChecksum32(Buf, BufSize);
+ hashXOR8:
+ PByte(Digest)^ := CalcXOR8(Buf, BufSize);
+ hashXOR16:
+ PWord(Digest)^ := CalcXOR16(Buf, BufSize);
+ hashXOR32:
+ PLongWord(Digest)^ := CalcXOR32(Buf, BufSize);
+ hashCRC16:
+ PWord(Digest)^ := CalcCRC16(Buf, BufSize);
+ hashCRC32:
+ PLongWord(Digest)^ := CalcCRC32(Buf, BufSize);
+ hashMD5:
+ P128BitDigest(Digest)^ := CalcMD5(Buf, BufSize);
+ hashSHA1:
+ P160BitDigest(Digest)^ := CalcSHA1(Buf, BufSize);
+ hashSHA256:
+ P256BitDigest(Digest)^ := CalcSHA256(Buf, BufSize);
+ hashSHA512:
+ P512BitDigest(Digest)^ := CalcSHA512(Buf, BufSize);
+ hashHMAC_MD5:
+ P128BitDigest(Digest)^ := CalcHMAC_MD5(nil, 0, Buf, BufSize);
+ hashHMAC_SHA1:
+ P160BitDigest(Digest)^ := CalcHMAC_SHA1(nil, 0, Buf, BufSize);
+ hashHMAC_SHA256:
+ P256BitDigest(Digest)^ := CalcHMAC_SHA256(nil, 0, Buf, BufSize);
+ hashHMAC_SHA512:
+ P512BitDigest(Digest)^ := CalcHMAC_SHA512(nil, 0, Buf, BufSize);
+ else
+ raise EHashError.Create(hashInvalidHashType);
+ end;
+end;
+
+procedure CalculateHash(const HashType: THashType; const Buf; const BufSize: Integer; const Digest: Pointer; const Key: AnsiString);
+begin
+ CalculateHash(HashType, Buf, BufSize, Digest, Pointer(Key), Length(Key));
+end;
+
+procedure CalculateHash(const HashType: THashType; const Buf: AnsiString; const Digest: Pointer; const Key: AnsiString);
+begin
+ CalculateHash(HashType, Pointer(Buf)^, Length(Buf), Digest, Key);
+end;
+
+{ }
+{ System helper functions }
+{ }
+resourcestring
+ SSystemError = 'System error #%s';
+
+{ }
+{ AHash }
+{ }
+class function AHash.BlockSize: Integer;
+begin
+ Result := - 1;
+end;
+
+procedure AHash.ProcessFinalBuf(const Buf; const BufSize: Integer; const TotalSize: Int64);
+begin
+ ProcessBuf(Buf, BufSize);
+end;
+
+procedure AHash.Init(const Digest: Pointer; const Key: Pointer; const KeySize: Integer);
+begin
+ Assert(Assigned(Digest));
+ FDigest := Digest;
+ FTotalSize := 0;
+ InitHash(Digest, Key, KeySize);
+end;
+
+procedure AHash.Init(const Digest: Pointer; const Key: AnsiString);
+begin
+ Init(Digest, Pointer(Key), Length(Key));
+end;
+
+procedure AHash.HashBuf(const Buf; const BufSize: Integer; const FinalBuf: Boolean);
+var
+ I, D: Integer;
+ P : PAnsiChar;
+begin
+ Inc(FTotalSize, BufSize);
+
+ D := BlockSize;
+ if D < 0 then
+ D := 64;
+ P := @Buf;
+ I := (BufSize div D) * D;
+ if I > 0 then
+ begin
+ ProcessBuf(P^, I);
+ Inc(P, I);
+ end;
+
+ I := BufSize mod D;
+ if FinalBuf then
+ ProcessFinalBuf(P^, I, FTotalSize)
+ else
+ if I > 0 then
+ raise EHashError.Create(hashInvalidBufferSize, 'Non final buffer must be multiple of block size');
+end;
+
+procedure AHash.HashFile(const FileName: string; const Offset: Int64; const MaxCount: Int64);
+const
+ ChunkSize = 8192;
+var
+ Handle: Integer;
+ Buf : Pointer;
+ I, C : Integer;
+ Left : Int64;
+ Fin : Boolean;
+begin
+ if FileName = '' then
+ raise EHashError.Create(hashInvalidFileName);
+ Handle := FileOpen(FileName, fmOpenReadWrite or fmShareDenyNone);
+ if Handle = - 1 then
+ raise EHashError.Create(hashFileOpenError, GetLastErrorText);
+ if Offset > 0 then
+ I := FileSeek(Handle, Offset, 0)
+ else
+ if Offset < 0 then
+ I := FileSeek(Handle, Offset, 2)
+ else
+ I := 0;
+ if I = - 1 then
+ raise EHashError.Create(hashFileSeekError, GetLastErrorText);
+ try
+ GetMem(Buf, ChunkSize);
+ try
+ if MaxCount < 0 then
+ Left := high(Int64)
+ else
+ Left := MaxCount;
+ repeat
+ if Left > ChunkSize then
+ C := ChunkSize
+ else
+ C := Left;
+ if C = 0 then
+ begin
+ I := 0;
+ Fin := True;
+ end else
+ begin
+ I := FileRead(Handle, Buf^, C);
+ if I = - 1 then
+ raise EHashError.Create(hashFileReadError, GetLastErrorText);
+ Dec(Left, I);
+ Fin := (I < C) or (Left <= 0);
+ end;
+ HashBuf(Buf^, I, Fin);
+ until Fin;
+ finally
+ FreeMem(Buf, ChunkSize);
+ end;
+ finally
+ FileClose(Handle);
+ end;
+end;
+
+{ }
+{ TChecksum32Hash }
+{ }
+procedure TChecksum32Hash.InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer);
+begin
+ PLongWord(Digest)^ := 0;
+end;
+
+procedure TChecksum32Hash.ProcessBuf(const Buf; const BufSize: Integer);
+begin
+ PLongWord(FDigest)^ := PLongWord(FDigest)^ + CalcChecksum32(Buf, BufSize);
+end;
+
+class function TChecksum32Hash.DigestSize: Integer;
+begin
+ Result := 4;
+end;
+
+{ }
+{ TXOR8Hash }
+{ }
+procedure TXOR8Hash.InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer);
+begin
+ PByte(Digest)^ := 0;
+end;
+
+procedure TXOR8Hash.ProcessBuf(const Buf; const BufSize: Integer);
+begin
+ PByte(FDigest)^ := PByte(FDigest)^ xor CalcXOR8(Buf, BufSize);
+end;
+
+class function TXOR8Hash.DigestSize: Integer;
+begin
+ Result := 1;
+end;
+
+{ }
+{ TXOR16Hash }
+{ }
+procedure TXOR16Hash.InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer);
+begin
+ PWord(Digest)^ := 0;
+end;
+
+procedure TXOR16Hash.ProcessBuf(const Buf; const BufSize: Integer);
+begin
+ PWord(FDigest)^ := PWord(FDigest)^ xor CalcXOR16(Buf, BufSize);
+end;
+
+class function TXOR16Hash.DigestSize: Integer;
+begin
+ Result := 2;
+end;
+
+{ }
+{ TXOR32Hash }
+{ }
+procedure TXOR32Hash.InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer);
+begin
+ PLongWord(Digest)^ := 0;
+end;
+
+procedure TXOR32Hash.ProcessBuf(const Buf; const BufSize: Integer);
+begin
+ PLongWord(FDigest)^ := PLongWord(FDigest)^ xor CalcXOR32(Buf, BufSize);
+end;
+
+class function TXOR32Hash.DigestSize: Integer;
+begin
+ Result := 4;
+end;
+
+{ }
+{ TCRC16Hash }
+{ }
+procedure TCRC16Hash.InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer);
+begin
+ CRC16Init(PWord(Digest)^);
+end;
+
+procedure TCRC16Hash.ProcessBuf(const Buf; const BufSize: Integer);
+begin
+ PWord(FDigest)^ := CRC16Buf(PWord(FDigest)^, Buf, BufSize);
+end;
+
+class function TCRC16Hash.DigestSize: Integer;
+begin
+ Result := 2;
+end;
+
+{ }
+{ TCRC32Hash }
+{ }
+procedure TCRC32Hash.InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer);
+begin
+ CRC32Init(PLongWord(Digest)^);
+end;
+
+procedure TCRC32Hash.ProcessBuf(const Buf; const BufSize: Integer);
+begin
+ PLongWord(FDigest)^ := CRC32Buf(PLongWord(FDigest)^, Buf, BufSize);
+end;
+
+class function TCRC32Hash.DigestSize: Integer;
+begin
+ Result := 4;
+end;
+
+{ }
+{ TAdler32Hash }
+{ }
+procedure TAdler32Hash.InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer);
+begin
+ Adler32Init(PLongWord(Digest)^);
+end;
+
+procedure TAdler32Hash.ProcessBuf(const Buf; const BufSize: Integer);
+begin
+ PLongWord(FDigest)^ := Adler32Buf(PLongWord(FDigest)^, Buf, BufSize);
+end;
+
+class function TAdler32Hash.DigestSize: Integer;
+begin
+ Result := 4;
+end;
+
+{ }
+{ TELFHash }
+{ }
+procedure TELFHash.InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer);
+begin
+ ELFInit(PLongWord(Digest)^);
+end;
+
+procedure TELFHash.ProcessBuf(const Buf; const BufSize: Integer);
+begin
+ PLongWord(FDigest)^ := ELFBuf(PLongWord(FDigest)^, Buf, BufSize);
+end;
+
+class function TELFHash.DigestSize: Integer;
+begin
+ Result := 4;
+end;
+
+{ }
+{ TMD5Hash }
+{ }
+procedure TMD5Hash.InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer);
+begin
+ MD5InitDigest(P128BitDigest(FDigest)^);
+end;
+
+procedure TMD5Hash.ProcessBuf(const Buf; const BufSize: Integer);
+begin
+ MD5Buf(P128BitDigest(FDigest)^, Buf, BufSize);
+end;
+
+procedure TMD5Hash.ProcessFinalBuf(const Buf; const BufSize: Integer; const TotalSize: Int64);
+begin
+ MD5FinalBuf(P128BitDigest(FDigest)^, Buf, BufSize, TotalSize);
+end;
+
+class function TMD5Hash.DigestSize: Integer;
+begin
+ Result := 16;
+end;
+
+class function TMD5Hash.BlockSize: Integer;
+begin
+ Result := 64;
+end;
+
+{ }
+{ TSHA1Hash }
+{ }
+procedure TSHA1Hash.InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer);
+begin
+ SHA1InitDigest(P160BitDigest(FDigest)^);
+end;
+
+procedure TSHA1Hash.ProcessBuf(const Buf; const BufSize: Integer);
+begin
+ SHA1Buf(P160BitDigest(FDigest)^, Buf, BufSize);
+end;
+
+procedure TSHA1Hash.ProcessFinalBuf(const Buf; const BufSize: Integer; const TotalSize: Int64);
+begin
+ SHA1FinalBuf(P160BitDigest(FDigest)^, Buf, BufSize, TotalSize);
+end;
+
+class function TSHA1Hash.DigestSize: Integer;
+begin
+ Result := 20;
+end;
+
+class function TSHA1Hash.BlockSize: Integer;
+begin
+ Result := 64;
+end;
+
+{ }
+{ TSHA256Hash }
+{ }
+procedure TSHA256Hash.InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer);
+begin
+ SHA256InitDigest(P256BitDigest(FDigest)^);
+end;
+
+procedure TSHA256Hash.ProcessBuf(const Buf; const BufSize: Integer);
+begin
+ SHA256Buf(P256BitDigest(FDigest)^, Buf, BufSize);
+end;
+
+procedure TSHA256Hash.ProcessFinalBuf(const Buf; const BufSize: Integer; const TotalSize: Int64);
+begin
+ SHA256FinalBuf(P256BitDigest(FDigest)^, Buf, BufSize, TotalSize);
+end;
+
+class function TSHA256Hash.DigestSize: Integer;
+begin
+ Result := 32;
+end;
+
+class function TSHA256Hash.BlockSize: Integer;
+begin
+ Result := 64;
+end;
+
+{ }
+{ TSHA512Hash }
+{ }
+procedure TSHA512Hash.InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer);
+begin
+ SHA512InitDigest(P512BitDigest(FDigest)^);
+end;
+
+procedure TSHA512Hash.ProcessBuf(const Buf; const BufSize: Integer);
+begin
+ SHA512Buf(P512BitDigest(FDigest)^, Buf, BufSize);
+end;
+
+procedure TSHA512Hash.ProcessFinalBuf(const Buf; const BufSize: Integer; const TotalSize: Int64);
+begin
+ SHA512FinalBuf(P512BitDigest(FDigest)^, Buf, BufSize, TotalSize);
+end;
+
+class function TSHA512Hash.DigestSize: Integer;
+begin
+ Result := 64;
+end;
+
+class function TSHA512Hash.BlockSize: Integer;
+begin
+ Result := 128;
+end;
+
+{ }
+{ THMAC_MD5Hash }
+{ }
+destructor THMAC_MD5Hash.Destroy;
+begin
+ SecureClear512(FKey);
+ inherited Destroy;
+end;
+
+procedure THMAC_MD5Hash.InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer);
+begin
+ HMAC_MD5Init(Key, KeySize, P128BitDigest(FDigest)^, FKey);
+end;
+
+procedure THMAC_MD5Hash.ProcessBuf(const Buf; const BufSize: Integer);
+begin
+ HMAC_MD5Buf(P128BitDigest(FDigest)^, Buf, BufSize);
+end;
+
+procedure THMAC_MD5Hash.ProcessFinalBuf(const Buf; const BufSize: Integer; const TotalSize: Int64);
+begin
+ HMAC_MD5FinalBuf(FKey, P128BitDigest(FDigest)^, Buf, BufSize, TotalSize);
+end;
+
+class function THMAC_MD5Hash.DigestSize: Integer;
+begin
+ Result := 16;
+end;
+
+class function THMAC_MD5Hash.BlockSize: Integer;
+begin
+ Result := 64;
+end;
+
+{ }
+{ THMAC_SHA1Hash }
+{ }
+destructor THMAC_SHA1Hash.Destroy;
+begin
+ SecureClear512(FKey);
+ inherited Destroy;
+end;
+
+procedure THMAC_SHA1Hash.InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer);
+begin
+ HMAC_SHA1Init(Key, KeySize, P160BitDigest(FDigest)^, FKey);
+end;
+
+procedure THMAC_SHA1Hash.ProcessBuf(const Buf; const BufSize: Integer);
+begin
+ HMAC_SHA1Buf(P160BitDigest(FDigest)^, Buf, BufSize);
+end;
+
+procedure THMAC_SHA1Hash.ProcessFinalBuf(const Buf; const BufSize: Integer; const TotalSize: Int64);
+begin
+ HMAC_SHA1FinalBuf(FKey, P160BitDigest(FDigest)^, Buf, BufSize, TotalSize);
+end;
+
+class function THMAC_SHA1Hash.DigestSize: Integer;
+begin
+ Result := 20;
+end;
+
+class function THMAC_SHA1Hash.BlockSize: Integer;
+begin
+ Result := 64;
+end;
+
+{ }
+{ THMAC_SHA256Hash }
+{ }
+destructor THMAC_SHA256Hash.Destroy;
+begin
+ SecureClear512(FKey);
+ inherited Destroy;
+end;
+
+procedure THMAC_SHA256Hash.InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer);
+begin
+ HMAC_SHA256Init(Key, KeySize, P256BitDigest(FDigest)^, FKey);
+end;
+
+procedure THMAC_SHA256Hash.ProcessBuf(const Buf; const BufSize: Integer);
+begin
+ HMAC_SHA256Buf(P256BitDigest(FDigest)^, Buf, BufSize);
+end;
+
+procedure THMAC_SHA256Hash.ProcessFinalBuf(const Buf; const BufSize: Integer; const TotalSize: Int64);
+begin
+ HMAC_SHA256FinalBuf(FKey, P256BitDigest(FDigest)^, Buf, BufSize, TotalSize);
+end;
+
+class function THMAC_SHA256Hash.DigestSize: Integer;
+begin
+ Result := 32;
+end;
+
+class function THMAC_SHA256Hash.BlockSize: Integer;
+begin
+ Result := 64;
+end;
+
+{ }
+{ THMAC_SHA512Hash }
+{ }
+destructor THMAC_SHA512Hash.Destroy;
+begin
+ SecureClear1024(FKey);
+ inherited Destroy;
+end;
+
+procedure THMAC_SHA512Hash.InitHash(const Digest: Pointer; const Key: Pointer; const KeySize: Integer);
+begin
+ HMAC_SHA512Init(Key, KeySize, P512BitDigest(FDigest)^, FKey);
+end;
+
+procedure THMAC_SHA512Hash.ProcessBuf(const Buf; const BufSize: Integer);
+begin
+ HMAC_SHA512Buf(P512BitDigest(FDigest)^, Buf, BufSize);
+end;
+
+procedure THMAC_SHA512Hash.ProcessFinalBuf(const Buf; const BufSize: Integer; const TotalSize: Int64);
+begin
+ HMAC_SHA512FinalBuf(FKey, P512BitDigest(FDigest)^, Buf, BufSize, TotalSize);
+end;
+
+class function THMAC_SHA512Hash.DigestSize: Integer;
+begin
+ Result := 64;
+end;
+
+class function THMAC_SHA512Hash.BlockSize: Integer;
+begin
+ Result := 128;
+end;
+
+{ }
+{ HashString }
+{ }
+function HashString(const StrBuf: Pointer; const StrLength: Integer; const Slots: LongWord; const CaseSensitive: Boolean): LongWord;
+var
+ P : PAnsiChar;
+ I, J: Integer;
+
+ procedure CRC32StrBuf(const Size: Integer);
+ begin
+ if CaseSensitive then
+ Result := CRC32Buf(Result, P^, Size)
+ else
+ Result := CRC32BufNoCase(Result, P^, Size);
+ end;
+
+begin
+ // Return 0 for an empty string
+ Result := 0;
+ if (StrLength <= 0) or not Assigned(StrBuf) then
+ exit;
+
+ if not CRC32TableInit then
+ InitCRC32Table;
+ Result := $FFFFFFFF;
+ P := StrBuf;
+
+ if StrLength <= 48 then // Hash everything for short strings
+ CRC32StrBuf(StrLength)
+ else
+ begin
+ // Hash first 16 bytes
+ CRC32StrBuf(16);
+
+ // Hash last 16 bytes
+ Inc(P, StrLength - 16);
+ CRC32StrBuf(16);
+
+ // Hash 16 bytes sampled from rest of string
+ I := (StrLength - 48) div 16;
+ P := StrBuf;
+ Inc(P, 16);
+ for J := 1 to 16 do
+ begin
+ CRC32StrBuf(1);
+ Inc(P, I + 1);
+ end;
+ end;
+
+ // Mod into slots
+ if (Slots <> 0) and (Slots <> high(LongWord)) then
+ Result := Result mod Slots;
+end;
+
+function HashString(const S: AnsiString; const Slots: LongWord; const CaseSensitive: Boolean): LongWord;
+begin
+ Result := HashString(Pointer(S), Length(S), Slots, CaseSensitive);
+end;
+
+{ }
+{ Hash by THashType }
+{ }
+const
+ HashTypeClasses: array [THashType] of THashClass = (
+ TChecksum32Hash, TXOR8Hash, TXOR16Hash, TXOR32Hash,
+ TCRC16Hash, TCRC32Hash,
+ TAdler32Hash,
+ TELFHash,
+ TMD5Hash, TSHA1Hash, TSHA256Hash, TSHA512Hash,
+ THMAC_MD5Hash, THMAC_SHA1Hash, THMAC_SHA256Hash, THMAC_SHA512Hash);
+
+function GetHashClassByType(const HashType: THashType): THashClass;
+begin
+ Result := HashTypeClasses[HashType];
+end;
+
+function GetDigestSize(const HashType: THashType): Integer;
+begin
+ Result := GetHashClassByType(HashType).DigestSize;
+end;
+
+end.
diff --git a/EvilWorks.Design.HTTPHeadersEditor.dfm b/EvilWorks.Design.HTTPHeadersEditor.dfm
new file mode 100644
index 0000000..e91e6c1
--- /dev/null
+++ b/EvilWorks.Design.HTTPHeadersEditor.dfm
@@ -0,0 +1,165 @@
+object HTTPHeadersPropertyEditorForm: THTTPHeadersPropertyEditorForm
+ Left = 0
+ Top = 0
+ BorderIcons = [biSystemMenu]
+ Caption = 'Edit headers...'
+ ClientHeight = 347
+ ClientWidth = 465
+ Color = clWindow
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -11
+ Font.Name = 'Segoe UI'
+ Font.Style = []
+ OldCreateOrder = False
+ Position = poOwnerFormCenter
+ OnCreate = FormCreate
+ OnDestroy = FormDestroy
+ DesignSize = (
+ 465
+ 347)
+ PixelsPerInch = 96
+ TextHeight = 13
+ object bvlFooter: TBevel
+ Left = 0
+ Top = 312
+ Width = 465
+ Height = 2
+ Align = alBottom
+ ExplicitLeft = 192
+ ExplicitTop = 136
+ ExplicitWidth = 50
+ end
+ object lblValue: TLabel
+ Left = 192
+ Top = 232
+ Width = 32
+ Height = 13
+ Anchors = [akLeft, akBottom]
+ Caption = '&Value:'
+ FocusControl = EdtValue
+ end
+ object lblKey: TLabel
+ Left = 8
+ Top = 232
+ Width = 20
+ Height = 13
+ Anchors = [akLeft, akBottom]
+ Caption = '&Key:'
+ FocusControl = EdtKey
+ end
+ object lblHeaders: TLabel
+ Left = 8
+ Top = 8
+ Width = 45
+ Height = 13
+ Caption = '&Headers:'
+ FocusControl = lvHeaders
+ end
+ object pnlFooter: TPanel
+ Left = 0
+ Top = 314
+ Width = 465
+ Height = 33
+ Align = alBottom
+ BevelOuter = bvNone
+ ParentBackground = False
+ TabOrder = 0
+ object btnOK: TButton
+ AlignWithMargins = True
+ Left = 305
+ Top = 5
+ Width = 75
+ Height = 23
+ Margins.Left = 0
+ Margins.Top = 5
+ Margins.Right = 5
+ Margins.Bottom = 5
+ Align = alRight
+ Caption = '&OK'
+ Default = True
+ ModalResult = 1
+ TabOrder = 0
+ end
+ object btnCancel: TButton
+ AlignWithMargins = True
+ Left = 385
+ Top = 5
+ Width = 75
+ Height = 23
+ Margins.Left = 0
+ Margins.Top = 5
+ Margins.Right = 5
+ Margins.Bottom = 5
+ Align = alRight
+ Cancel = True
+ Caption = '&Cancel'
+ ModalResult = 2
+ TabOrder = 1
+ end
+ end
+ object lvHeaders: TListView
+ Left = 8
+ Top = 24
+ Width = 449
+ Height = 193
+ Anchors = [akLeft, akTop, akRight, akBottom]
+ Columns = <
+ item
+ Caption = 'Key'
+ Width = 180
+ end
+ item
+ Caption = 'Value'
+ Width = 240
+ end>
+ GridLines = True
+ ReadOnly = True
+ RowSelect = True
+ TabOrder = 1
+ ViewStyle = vsReport
+ end
+ object BtnClear: TButton
+ Left = 384
+ Top = 280
+ Width = 75
+ Height = 25
+ Anchors = [akRight, akBottom]
+ Caption = 'C&lear'
+ TabOrder = 2
+ end
+ object BtnDelete: TButton
+ Left = 88
+ Top = 280
+ Width = 75
+ Height = 25
+ Anchors = [akLeft, akBottom]
+ Caption = '&Delete'
+ TabOrder = 3
+ end
+ object BtnAdd: TButton
+ Left = 8
+ Top = 280
+ Width = 75
+ Height = 25
+ Anchors = [akLeft, akBottom]
+ Caption = '&Add'
+ TabOrder = 4
+ end
+ object EdtValue: TEdit
+ Left = 192
+ Top = 248
+ Width = 265
+ Height = 21
+ Anchors = [akLeft, akRight, akBottom]
+ TabOrder = 5
+ end
+ object EdtKey: TEdit
+ Left = 8
+ Top = 248
+ Width = 177
+ Height = 21
+ Anchors = [akLeft, akBottom]
+ TabOrder = 6
+ end
+end
diff --git a/EvilWorks.Design.HTTPHeadersEditor.pas b/EvilWorks.Design.HTTPHeadersEditor.pas
new file mode 100644
index 0000000..00cd0eb
--- /dev/null
+++ b/EvilWorks.Design.HTTPHeadersEditor.pas
@@ -0,0 +1,124 @@
+unit EvilWorks.Design.HTTPHeadersEditor;
+
+{$R *.dfm}
+
+interface
+
+uses
+ Winapi.Windows,
+ Winapi.Messages,
+ System.SysUtils,
+ System.Variants,
+ System.Classes,
+ Vcl.Graphics,
+ Vcl.Controls,
+ Vcl.Forms,
+ Vcl.Dialogs,
+ Vcl.StdCtrls,
+ Vcl.ComCtrls,
+ Vcl.ExtCtrls,
+ DesignEditors,
+ DesignIntf,
+ EvilWorks.Web.HTTP;
+
+type
+ { }
+ THTTPHeadersProperty = class(TClassProperty)
+ public
+ procedure Edit; override;
+ function GetAttributes: TPropertyAttributes; override;
+ end;
+
+ { }
+ THTTPHeadersPropertyEditorForm = class(TForm)
+ pnlFooter: TPanel;
+ btnOK: TButton;
+ btnCancel: TButton;
+ bvlFooter: TBevel;
+ lvHeaders: TListView;
+ BtnClear: TButton;
+ BtnDelete: TButton;
+ BtnAdd: TButton;
+ EdtValue: TEdit;
+ EdtKey: TEdit;
+ lblValue: TLabel;
+ lblKey: TLabel;
+ lblHeaders: TLabel;
+ procedure FormCreate(Sender: TObject);
+ procedure FormDestroy(Sender: TObject);
+ private
+ FHeaders: THTTPMessage;
+ public
+ procedure ReloadHeaders;
+ property HTTPHeaders: THTTPMessage read FHeaders write FHeaders;
+ end;
+
+implementation
+
+{ ==================== }
+{ THTTPHeadersProperty }
+{ ==================== }
+
+{ }
+procedure THTTPHeadersProperty.Edit;
+var
+ frm: THTTPHeadersPropertyEditorForm;
+begin
+ Application.CreateForm(THTTPHeadersPropertyEditorForm, frm);
+ try
+ frm.Caption := Self.GetName;
+ frm.HTTPHeaders.Assign(THTTPMessage(GetOrdValue));
+ frm.ReloadHeaders;
+ if (frm.ShowModal = mrOk) then
+ begin
+ THTTPMessage(GetOrdValue).Assign(frm.HTTPHeaders);
+ Modified;
+ end;
+ finally
+ frm.Free;
+ end;
+end;
+
+{ }
+function THTTPHeadersProperty.GetAttributes: TPropertyAttributes;
+begin
+ Result := [paDialog, paMultiSelect, paAutoUpdate];
+end;
+
+{ ============================== }
+{ THTTPHeadersPropertyEditorForm }
+{ ============================== }
+
+{ }
+procedure THTTPHeadersPropertyEditorForm.FormCreate(Sender: TObject);
+begin
+ FHeaders := THTTPMessage.Create;
+end;
+
+{ }
+procedure THTTPHeadersPropertyEditorForm.FormDestroy(Sender: TObject);
+begin
+ FHeaders.Free;
+end;
+
+{ }
+procedure THTTPHeadersPropertyEditorForm.ReloadHeaders;
+var
+ i : integer;
+ li: TListItem;
+begin
+ lvHeaders.Items.BeginUpdate;
+ try
+ lvHeaders.Clear;
+ for i := 0 to HTTPHeaders.Count - 1 do
+ begin
+ li := lvHeaders.Items.Add;
+ li.Caption := HTTPHeaders[i].Key;
+ li.SubItems.Add(HTTPHeaders[i].Val);
+ end;
+ finally
+ lvHeaders.Items.EndUpdate;
+ end;
+end;
+
+end.
diff --git a/EvilWorks.Generics.AVLTree.pas b/EvilWorks.Generics.AVLTree.pas
new file mode 100644
index 0000000..4758ffc
--- /dev/null
+++ b/EvilWorks.Generics.AVLTree.pas
@@ -0,0 +1,632 @@
+//
+// EvilLibrary by Vedran Vuk 2010-2012
+//
+// Name: EvilWorks.DataStructures.AVLTree
+// Description: An Generic AVL tree implementation.
+// Largely a translation from C by Julienne Walker but implemented as a generic class
+// with independant Key (Node key) and Val (Node data).
+// http://eternallyconfuzzled.com/tuts/datastructures/jsw_tut_avl.aspx
+// File last change date: November 16th. 2012
+// File version: Dev 0.0.0
+// Licence: Free.
+//
+
+unit EvilWorks.Generics.AVLTree;
+
+interface
+
+uses
+ System.SysUtils;
+
+type
+ { Exceptions }
+ EAVLTree = class(Exception); // Base exception
+ EAVLTreeItemNotFound = class(EAVLTree); // Used in GetItem().
+
+ { TAVLTree }
+ { A Generic balanced binary tree implementation. }
+ TAVLTree = class
+ private const
+ HEIGHT_LIMIT = 65536;
+ public type
+ TCompareFunc = reference to function(const aKeyA, aKeyB: TKey): integer;
+ TReleaseKeyProc = reference to procedure(var aKey: TKey);
+ TReleaseValProc = reference to procedure(var aVal: TVal);
+ private type
+
+ { TAVLNode }
+ PAVLNode = ^TAVLNode;
+
+ TAVLNode = record
+ Key: TKey;
+ Val: TVal;
+ Bal: integer;
+ Lnk: array [boolean] of PAVLNode;
+ end;
+
+ { TTokensEnumerator }
+ TAVLTreeEnumerator = class
+ private
+ FTree: TAVLTree;
+ FCurr: PAVLNode;
+ FPath: array [0 .. HEIGHT_LIMIT] of PAVLNode;
+ FTop : cardinal;
+ public
+ constructor Create(aTree: TAVLTree);
+ function GetCurrent: TVal; inline;
+ function MoveNext: Boolean; inline;
+ property Current: TVal read GetCurrent;
+ end;
+
+ private
+ FRoot : PAVLNode;
+ FCount : cardinal;
+ FCompare : TCompareFunc;
+ FReleaseKey: TReleaseKeyProc;
+ FReleaseVal: TReleaseValProc;
+ function GetCount: integer;
+ function GetItem(const aKey: TKey): TVal;
+ procedure SetItem(const aKey: TKey; const aVal: TVal);
+ protected
+ procedure RotateSingle(var aRoot: PAVLNode; aDir: boolean);
+ procedure RotateDouble(var aRoot: PAVLNode; aDir: boolean);
+ procedure AdjustBalance(var aRoot: PAVLNode; aDir: boolean; aBalance: integer);
+ procedure BalanceAfterInsert(var aRoot: PAVLNode; aDir: boolean);
+ procedure BalanceAfterRemove(var aRoot: PAVLNode; aDir: boolean; var aDone: boolean);
+ procedure RemoveNode(const aKey: TKey; const aFreeData: boolean; var aSaveKey: TKey; var aSaveVal: TVal);
+ function Find(const aKey: TKey): PAVLNode;
+ public
+ constructor Create(const aCompare: TCompareFunc; const aReleaseKey: TReleaseKeyProc; const aReleaseVal: TReleaseValProc);
+ destructor Destroy; override;
+ procedure Assign(const aSource: TAVLTree);
+
+ function GetEnumerator: TAVLTreeEnumerator;
+
+ procedure Insert(const aKey: TKey; const aVal: TVal);
+ procedure Delete(const aKey: TKey);
+ procedure ReKey(const aOldKey, aNewKey: TKey);
+ procedure Clear;
+
+ property Items[const aKey: TKey]: TVal read GetItem write SetItem; default;
+ property Count: integer read GetCount;
+ function Exists(const aKey: TKey): boolean;
+ end;
+
+implementation
+
+{ ======================================= }
+{ TAVLTree.TAVLTreeEnumerator }
+{ ======================================= }
+
+{ Constructor. }
+constructor TAVLTree.TAVLTreeEnumerator.Create(aTree: TAVLTree);
+begin
+ FTree := aTree;
+ FCurr := nil;
+ FTop := 0;
+end;
+
+{ Gets curent item for the iterator. }
+function TAVLTree.TAVLTreeEnumerator.GetCurrent: TVal;
+begin
+ Result := FCurr^.Val;
+end;
+
+{ Advances to next item for the iterator. }
+function TAVLTree.TAVLTreeEnumerator.MoveNext: Boolean;
+var
+ last: PAVLNode;
+begin
+ if (FCurr = nil) then
+ begin
+ FCurr := FTree.FRoot;
+ FTop := 0;
+
+ // build a path to work with
+ if (FCurr <> nil) then
+ begin
+ while (FCurr^.Lnk[False] <> nil) do
+ begin
+ FPath[FTop] := FCurr;
+ Inc(FTop);
+ FCurr := FCurr^.Lnk[False];
+ end;
+ end;
+ end
+ else
+ begin
+ if (FCurr^.Lnk[True] <> nil) then
+ begin
+ // continue down this branch
+ FPath[FTop] := FCurr;
+ Inc(FTop);
+ FCurr := FCurr^.Lnk[True];
+
+ while (FCurr^.Lnk[not True] <> nil) do
+ begin
+ FPath[FTop] := FCurr;
+ Inc(FTop);
+ FCurr := FCurr^.Lnk[not True];
+ end;
+ end
+ else
+ begin
+ // move to the next branch
+ repeat
+ if (FTop = 0) then
+ begin
+ FCurr := nil;
+ Break;
+ end;
+
+ last := FCurr;
+ Dec(FTop);
+ FCurr := FPath[FTop];
+ until (last <> FCurr^.Lnk[True]);
+ end;
+ end;
+ Result := (FCurr <> nil);
+end;
+
+{ ==================== }
+{ TAVLTree }
+{ ==================== }
+
+{ Constructor. aCompare compares two TVal items, aReleaseKey disposes of TKey, aReleaseVal of TVal. }
+constructor TAVLTree.Create(const aCompare: TCompareFunc; const aReleaseKey: TReleaseKeyProc; const aReleaseVal: TReleaseValProc);
+begin
+ FRoot := nil;
+ FCompare := aCompare;
+ FReleaseKey := aReleaseKey;
+ FReleaseVal := aReleaseVal;
+ FCount := 0
+end;
+
+{ Destructor. }
+destructor TAVLTree.Destroy;
+begin
+ Clear;
+ inherited;
+end;
+
+{ Assign from an instance of the same type. }
+procedure TAVLTree.Assign(const aSource: TAVLTree);
+begin
+
+end;
+
+{ Implements GetEnumerator for for in iterator. }
+function TAVLTree.GetEnumerator: TAVLTreeEnumerator;
+begin
+ Result := TAVLTreeEnumerator.Create(Self);
+end;
+
+{ Performs a single rotation. }
+procedure TAVLTree.RotateSingle(var aRoot: PAVLNode; aDir: boolean);
+var
+ save: PAVLNode;
+begin
+ save := aRoot^.Lnk[not aDir];
+ aRoot^.Lnk[not aDir] := save^.Lnk[aDir];
+ save^.Lnk[aDir] := aRoot;
+ aRoot := save;
+end;
+
+{ Performs a double rotation. }
+procedure TAVLTree.RotateDouble(var aRoot: PAVLNode; aDir: boolean);
+var
+ save: PAVLNode;
+begin
+ save := aRoot^.Lnk[not aDir]^.Lnk[aDir];
+ aRoot^.Lnk[not aDir]^.Lnk[aDir] := save^.Lnk[not aDir];
+ save^.Lnk[not aDir] := aRoot^.Lnk[not aDir];
+ aRoot^.Lnk[not aDir] := save;
+ save := aRoot^.Lnk[not aDir];
+ aRoot^.Lnk[not aDir] := save^.Lnk[aDir];
+ save^.Lnk[aDir] := aRoot;
+ aRoot := save;
+end;
+
+{ Balances the tree height. }
+procedure TAVLTree.AdjustBalance(var aRoot: PAVLNode; aDir: boolean; aBalance: integer);
+var
+ n, nn: PAVLNode;
+begin
+ n := aRoot^.Lnk[aDir];
+ nn := n^.Lnk[not aDir];
+ if (nn^.Bal = 0) then
+ begin
+ aRoot^.Bal := 0;
+ n^.Bal := 0;
+ end
+ else if (nn^.Bal = aBalance) then
+ begin
+ aRoot^.Bal := - aBalance;
+ n^.Bal := 0;
+ end
+ else
+ begin
+ aRoot^.Bal := 0;
+ n^.Bal := aBalance;
+ end;
+ nn^.Bal := 0;
+end;
+
+{ Balances the tree height after insertion. }
+procedure TAVLTree.BalanceAfterInsert(var aRoot: PAVLNode; aDir: boolean);
+var
+ n : PAVLNode;
+ bal: integer;
+begin
+ n := aRoot^.Lnk[aDir];
+ if (not aDir) then
+ bal := - 1
+ else
+ bal := + 1;
+ if (n^.Bal = bal) then
+ begin
+ aRoot^.Bal := 0;
+ n^.Bal := 0;
+ RotateSingle(aRoot, not aDir);
+ end
+ else
+ begin
+ AdjustBalance(aRoot, aDir, bal);
+ RotateDouble(aRoot, not aDir);
+ end;
+end;
+
+{ Balances the tree height after deletion. }
+procedure TAVLTree.BalanceAfterRemove(var aRoot: PAVLNode; aDir: boolean; var aDone: boolean);
+var
+ n : PAVLNode;
+ bal: integer;
+begin
+ n := aRoot^.Lnk[not aDir];
+ if (not aDir) then
+ bal := - 1
+ else
+ bal := + 1;
+ if (n^.Bal = - bal) then
+ begin
+ aRoot^.Bal := 0;
+ n^.Bal := 0;
+ RotateSingle(aRoot, aDir);
+ end
+ else if (n^.Bal = bal) then
+ begin
+ AdjustBalance(aRoot, not aDir, - bal);
+ RotateDouble(aRoot, aDir);
+ end
+ else
+ begin
+ aRoot^.Bal := - bal;
+ n^.Bal := bal;
+ RotateSingle(aRoot, aDir);
+ aDone := True;
+ end;
+end;
+
+{ Internal function for removing a node. if aFreeData frees node, Key and Val, }
+{ otherwise returns Key in aSaveKey and Val in aSaveVal then removes the node. }
+procedure TAVLTree.RemoveNode(const aKey: TKey; const aFreeData: boolean; var aSaveKey: TKey; var aSaveVal: TVal);
+var
+ it : PAVLNode;
+ heir: PAVLNode;
+ save: TVal;
+ up : array [0 .. HEIGHT_LIMIT] of PAVLNode;
+ upd : array [0 .. HEIGHT_LIMIT - 1] of boolean;
+ top : integer;
+ done: boolean;
+ dir : boolean;
+begin
+ top := 0;
+ done := boolean(0);
+ if (FRoot <> nil) then
+ begin
+ it := FRoot;
+
+ // Search down the tree and save path
+ while (True) do
+ begin
+ if (it = nil) then
+ Exit
+ else if (FCompare(it^.Key, aKey) = 0) then
+ Break;
+
+ // Push direction and node onto stack
+ upd[top] := (FCompare(it^.Key, aKey) < 0);
+ up[top] := it;
+ it := it^.Lnk[upd[top]];
+ Inc(top);
+ end;
+
+ // Remove the node
+ if (it^.Lnk[False] = nil) or (it^.Lnk[True] = nil) then
+ begin
+ // Which child is not nil?
+ dir := (it^.Lnk[False] = nil);
+
+ // Fix parent
+ if (top <> 0) then
+ up[top - 1]^.Lnk[upd[top - 1]] := it^.Lnk[dir]
+ else
+ FRoot := it^.Lnk[dir];
+
+ if (aFreeData) then
+ begin
+ FReleaseKey(it^.Key);
+ FReleaseVal(it^.Val);
+ end
+ else
+ begin
+ aSaveKey := it^.Key;
+ aSaveVal := it^.Val;
+ end;
+ FreeMem(it);
+ end
+ else
+ begin
+ // Find the inorder successor
+ heir := it^.Lnk[True];
+
+ // Save this path too
+ upd[top] := True;
+ up[top] := it;
+ Inc(top);
+
+ while (heir^.Lnk[False] <> nil) do
+ begin
+ upd[top] := False;
+ up[top] := heir;
+ Inc(top);
+ heir := heir^.Lnk[False];
+ end;
+
+ // Swap data
+ save := it^.Val;
+ it^.Val := heir^.Val;
+ heir^.Val := save;
+
+ // Unlink successor and fix parent
+ up[top - 1]^.Lnk[(up[top - 1] = it)] := heir^.Lnk[True];
+
+ if (aFreeData) then
+ begin
+ FReleaseKey(it^.Key);
+ FReleaseVal(it^.Val);
+ end
+ else
+ begin
+ aSaveKey := it^.Key;
+ aSaveVal := it^.Val;
+ end;
+ FreeMem(heir);
+ end;
+
+ // Walk back up the search path
+ Dec(top);
+ while (top >= 0) and (not done) do
+ begin
+ // Update balance factors
+ if (upd[top]) then
+ up[top]^.Bal := up[top]^.Bal - 1
+ else
+ up[top]^.Bal := up[top]^.Bal + 1;
+
+ // Terminate or rebalance as neccesary
+ if (Abs(up[top]^.Bal) = 1) then
+ Break
+ else if (Abs(up[top]^.Bal) > 1) then
+ begin
+ BalanceAfterRemove(up[top], upd[top], done);
+
+ // Fix parent
+ if (top <> 0) then
+ up[top - 1]^.Lnk[upd[top - 1]] := up[top]
+ else
+ FRoot := up[0];
+ end;
+ Dec(top);
+ end;
+ Dec(FCount);
+ end;
+end;
+
+{ Searches for a node keyed with aKey. }
+function TAVLTree.Find(const aKey: TKey): PAVLNode;
+var
+ it : PAVLNode;
+ cmp: integer;
+begin
+ it := FRoot;
+
+ while (it <> nil) do
+ begin
+ cmp := FCompare(it^.Key, aKey);
+ if (cmp = 0) then
+ Break;
+ it := it^.Lnk[cmp < 0];
+ end;
+ Result := it;
+end;
+
+{ Inserts a new node keyed with aey with value aVal. }
+procedure TAVLTree.Insert(const aKey: TKey; const aVal: TVal);
+var
+ head : TAVLNode;
+ s, t, p, q: PAVLNode;
+ dir : boolean;
+begin
+ if (FRoot = nil) then
+ begin
+ FRoot := AllocMem(SizeOf(TAVLNode));
+ if (FRoot = nil) then
+ Exit;
+ FRoot^.Key := aKey;
+ FRoot^.Val := aVal;
+ end
+ else
+ begin
+ // If node of aKey exists, update its Val and exit.
+ s := Find(aKey);
+ if (s <> nil) then
+ begin
+ s^.Val := aVal;
+ Exit;
+ end;
+
+ // Set up false root to ease maintenance
+ FillChar(head, SizeOf(head), 0);
+ t := @head;
+ t^.Lnk[True] := FRoot;
+
+ // Search down the tree, saving rebalance points
+ s := t.Lnk[True];
+ p := t.Lnk[True];
+ while (True) do
+ begin
+ dir := (FCompare(p^.Key, aKey) < 0);
+ q := p^.Lnk[dir];
+
+ if (q = nil) then
+ Break;
+
+ if (q^.Bal <> 0) then
+ begin
+ t := p;
+ s := q;
+ end;
+
+ p := q;
+ end;
+
+ q := AllocMem(SizeOf(TAVLNode));
+ q^.Key := aKey;
+ q^.Val := aVal;
+ p^.Lnk[dir] := q;
+
+ if (q = nil) then
+ Exit;
+
+ // Update balance factors
+ p := s;
+ while (p <> q) do
+ begin
+ dir := (FCompare(p^.Key, aKey) < 0);
+
+ if (not dir) then
+ p^.Bal := p^.Bal - 1
+ else
+ p^.Bal := p^.Bal + 1;
+
+ p := p^.Lnk[dir];
+ end;
+
+ q := s; // Save rebalance point for parent fix
+
+ // Rebalance if necessary
+ if (Abs(s^.Bal) > 1) then
+ begin
+ dir := (FCompare(s^.Key, aKey) < 0);
+ BalanceAfterInsert(s, dir);
+ end;
+
+ // Fix parent
+ if (q = head.Lnk[True]) then
+ FRoot := s
+ else
+ t^.Lnk[(q = t^.Lnk[True])] := s;
+ end;
+ Inc(FCount);
+end;
+
+{ Deletes a node keyed with aKey. }
+procedure TAVLTree.Delete(const aKey: TKey);
+var
+ tempKey: TKey;
+ tempVal: TVal;
+begin
+ RemoveNode(aKey, True, tempKey, tempVal);
+end;
+
+{ Changes the Key of a node. }
+procedure TAVLTree.ReKey(const aOldKey, aNewKey: TKey);
+var
+ tempKey: TKey;
+ tempVal: TVal;
+begin
+ RemoveNode(aOldKey, False, tempKey, tempVal);
+ FReleaseKey(tempKey);
+ Insert(aNewKey, tempVal);
+end;
+
+{ Clears the tree. Disposition methods called for every node. }
+procedure TAVLTree.Clear;
+var
+ it : PAVLNode;
+ save: PAVLNode;
+begin
+ it := FRoot;
+
+ // Destruction by rotation
+ while (it <> nil) do
+ begin
+ if (it^.Lnk[False] = nil) then
+ begin
+ // Remove node
+ save := it^.Lnk[True];
+ FReleaseKey(it^.Key);
+ FReleaseVal(it^.Val);
+ FreeMem(it);
+ end
+ else
+ begin
+ // Rotate right
+ save := it^.Lnk[False];
+ it^.Lnk[False] := save^.Lnk[True];
+ save^.Lnk[True] := it;
+ end;
+ it := save;
+ end;
+ FRoot := nil;
+ FCount := 0;
+end;
+
+{ Checks if a node keyed with aKey exists. }
+function TAVLTree.Exists(const aKey: TKey): boolean;
+begin
+ Result := (Find(aKey) <> nil);
+end;
+
+{ Returns the count of tree nodes. }
+function TAVLTree.GetCount: integer;
+begin
+ Result := integer(FCount);
+end;
+
+{ Item getter. If not found raises EAVLTreeItemNotFound. }
+function TAVLTree.GetItem(const aKey: TKey): TVal;
+var
+ node: PAVLNode;
+begin
+ node := Find(aKey);
+ if (node = nil) then
+ raise EAVLTreeItemNotFound.Create('Item not found.');
+
+ Result := node^.Val;
+end;
+
+{ Item setter. If not found inserts new item. }
+procedure TAVLTree.SetItem(const aKey: TKey; const aVal: TVal);
+var
+ node: PAVLNode;
+begin
+ node := Find(aKey);
+ if (node <> nil) then
+ node^.Val := aVal
+ else
+ Insert(aKey, aVal);
+end;
+
+end.
diff --git a/EvilWorks.Generics.List.pas b/EvilWorks.Generics.List.pas
new file mode 100644
index 0000000..ca73761
--- /dev/null
+++ b/EvilWorks.Generics.List.pas
@@ -0,0 +1,354 @@
+//
+// EvilLibrary by Vedran Vuk 2010-2012
+//
+// Name: EvilWorks.DataStructures.AVLTree
+// Description: A Generic list implementation.
+// File last change date: November 17th. 2012
+// File version: Dev 0.0.0
+// Licence: Free.
+//
+
+unit EvilWorks.Generics.List;
+
+interface
+
+uses
+ System.SysUtils;
+
+type
+ EList = class(Exception);
+ EListIndexOutOfBounds = class(EList);
+
+ { TList }
+ { A Generic list. }
+ TList = class
+ public type
+ TCreateFunc = reference to function: T;
+ TDestroyProc = reference to procedure(var aItem: T);
+ TAssignProc = reference to procedure(const aFromItem: T; var aToItem: T);
+ TCompareFunc = reference to function(const aItemA, aItemB: T): integer;
+ private type
+
+ { TListEnumerator }
+ TListEnumerator = class
+ private
+ FIndex : integer;
+ FList: TList;
+ public
+ constructor Create(aList: TList);
+ function GetCurrent: T; inline;
+ function MoveNext: Boolean; inline;
+ property Current: T read GetCurrent;
+ end;
+
+ private
+ FItems : array of T;
+ FCount : integer;
+ FSorted : boolean;
+ FCreate : TCreateFunc;
+ FCompare: TCompareFunc;
+ FAssign : TAssignProc;
+ FDestroy: TDestroyProc;
+ function GetT(const aIndex: integer): T;
+ procedure SetT(const aIndex: integer; const Value: T);
+ protected
+ procedure QuickSort(const aStart, aEnd: integer);
+ public
+ constructor Create(const aCreate: TCreateFunc; const aDestroy: TDestroyProc; const aAssign: TAssignProc; const aCompare: TCompareFunc);
+ destructor Destroy; override;
+ procedure Assign(const aSource: TList);
+ function GetEnumerator: TListEnumerator;
+
+ function Add: T; overload;
+ function Add(const aItem: T): T; overload;
+ function AddSorted: T; overload;
+ function AddSorted(const aItem: T): T; overload;
+ function Insert(const aIndex: integer): T; overload;
+ function Insert(const aIndex: integer; const aItem: T): T; overload;
+ procedure Exchange(const aIndexA, aIndexB: integer);
+ procedure Delete(const aIndex: integer);
+ procedure Clear;
+
+ procedure Sort;
+ function IndexOf(const aVal: T): integer;
+
+ property Items[const aIndex: integer]: T read GetT write SetT; default;
+ property Count: integer read FCount;
+ property Sorted: boolean read FSorted;
+ end;
+
+implementation
+
+{ ======================== }
+{ TList.TListEnumerator }
+{ ======================== }
+
+{ Constructor. }
+constructor TList.TListEnumerator.Create(aList: TList);
+begin
+ inherited Create;
+ FIndex := - 1;
+ FList := aList;
+end;
+
+{ Gets curent item for the iterator. }
+function TList.TListEnumerator.GetCurrent: T;
+begin
+ Result := FList[FIndex];
+end;
+
+{ Advances to next item for the iterator. }
+function TList.TListEnumerator.MoveNext: Boolean;
+begin
+ Result := (FIndex < FList.Count - 1);
+ if Result then
+ Inc(FIndex);
+end;
+
+{ ======== }
+{ TList }
+{ ======== }
+
+{ Constructor. }
+constructor TList.Create(const aCreate: TCreateFunc; const aDestroy: TDestroyProc; const aAssign: TAssignProc; const aCompare: TCompareFunc);
+begin
+ FCount := 0;
+ FSorted := False;
+ FCreate := aCreate;
+ FDestroy := aDestroy;
+ FAssign := aAssign;
+ FCompare := aCompare;
+end;
+
+{ Destructor. }
+destructor TList.Destroy;
+begin
+ Clear;
+ inherited;
+end;
+
+{ Assign from an instance of the same type. }
+procedure TList.Assign(const aSource: TList);
+var
+ i: integer;
+ c: T;
+begin
+ Clear;
+ for i := 0 to aSource.Count - 1 do
+ begin
+ c := Add;
+ FAssign(aSource[i], c);
+ end;
+end;
+
+{ Implements GetEnumerator. }
+function TList.GetEnumerator: TListEnumerator;
+begin
+ Result := TListEnumerator.Create(Self);
+end;
+
+{ Add a new item to the list. Uses aCreate function from constructor to create a new item. }
+function TList.Add: T;
+begin
+ Result := Add(FCreate);
+end;
+
+{ Add aItem to the list. }
+function TList.Add(const aItem: T): T;
+begin
+ Result := Insert(FCount, aItem);
+end;
+
+{ Add a new item to the list, sort if not already sorted. Adding is done using partitioning, fast. }
+{ Uses aCreate function from constructor to create a new item. }
+function TList.AddSorted: T;
+begin
+ Result := AddSorted(FCreate);
+end;
+
+{ Add aItem to the list, sort if not already sorted. Adding is done using partitioning, fast. }
+function TList.AddSorted(const aItem: T): T;
+var
+ loIdx, hiIdx, i: integer;
+begin
+ Sort;
+
+ if (FCount <> 0) then
+ begin
+ loIdx := 0;
+ hiIdx := FCount;
+ while (loIdx < hiIdx) do
+ begin
+ i := ((loIdx + hiIdx) shr 1);
+ if (FCompare(aItem, FItems[i]) = - 1) then
+ hiIdx := i
+ else
+ loIdx := i + 1;
+ end;
+ i := loIdx;
+ end
+ else
+ i := 0;
+
+ Insert(i, aItem);
+ // Insert unmarks FSorted, but the insert index is found using
+ // bisection and is 'sorted', so just re-mark as sorted.
+ FSorted := True;
+end;
+
+{ Add a new item to the list at aIndex. Uses aCreate function from constructor to create a new item. }
+{ If the list is sorted, Sorted state is broken and needs to be sorted again. }
+function TList.Insert(const aIndex: integer): T;
+begin
+ Result := Insert(FCount, FCreate);
+end;
+
+{ Add aItem to the list at aIndex. }
+{ If the list was sorted, Sorted state is broken and needs to be sorted again. }
+function TList.Insert(const aIndex: integer; const aItem: T): T;
+begin
+ if (aIndex < 0) or (aIndex > FCount) then
+ raise EArgumentOutOfRangeException.Create(Format('Index %d out of bounds %d.', [aIndex, FCount]));
+
+ SetLength(FItems, FCount + 1);
+ if (aIndex < FCount) then
+ System.Move(FItems[aIndex], FItems[aIndex + 1], (FCount - aIndex) * SizeOf(T));
+ FItems[aIndex] := aItem;
+ Inc(FCount);
+ FSorted := False;
+end;
+
+{ Exchange position of items at aIndexA and aIndexB. }
+{ If the list was sorted, Sorted state is broken and needs to be sorted again. }
+procedure TList.Exchange(const aIndexA, aIndexB: integer);
+var
+ temp: T;
+begin
+ temp := FItems[aIndexB];
+ FItems[aIndexB] := FItems[aIndexA];
+ FItems[aIndexA] := temp;
+ FSorted := False;
+end;
+
+{ Delete an item from the list at aIndex. Uses aDestroy from constructor to free the item. }
+procedure TList.Delete(const aIndex: integer);
+begin
+ if (aIndex < 0) or (aIndex > FCount) then
+ raise EArgumentOutOfRangeException.Create(Format('Index %d out of bounds %d.', [aIndex, FCount]));
+
+ FDestroy(FItems[aIndex]);
+ Dec(FCount);
+ if (aIndex < FCount) then
+ System.Move(FItems[aIndex + 1], FItems[aIndex], (FCount - aIndex) * SizeOf(T));
+end;
+
+{ Clear the list. Uses aDestroy from constructor to free each item. }
+procedure TList.Clear;
+var
+ i: integer;
+begin
+ for i := 0 to FCount - 1 do
+ FDestroy(FItems[i]);
+ SetLength(FItems, 0);
+ FCount := 0;
+end;
+
+{ Internal QuickSort function. Uses aCompare function from constructor to compare items when sorting. }
+procedure TList.QuickSort(const aStart, aEnd: integer);
+var
+ a: Integer;
+ i: Integer;
+ j: Integer;
+ p: Integer;
+begin
+ if (FCount <= 1) then
+ Exit;
+ a := aStart;
+ repeat
+ i := a;
+ j := aEnd;
+ p := (a + aEnd) shr 1;
+ repeat
+ while (FCompare(FItems[i], FItems[p]) < 0) do
+ Inc(i);
+ while (FCompare(FItems[j], FItems[p]) > 0) do
+ Dec(j);
+ if (i <= j) then
+ begin
+ if (i <> j) then
+ Exchange(i, j);
+ if (p = i) then
+ p := j
+ else if (p = j) then
+ p := i;
+ Inc(i);
+ Dec(j);
+ end;
+ until (i > j);
+ if (a < j) then
+ QuickSort(a, j);
+ a := i;
+ until (i >= aEnd);
+end;
+
+{ Sort the list. }
+procedure TList.Sort;
+begin
+ if (FSorted) then
+ Exit;
+
+ QuickSort(0, FCount - 1);
+ FSorted := True;
+end;
+
+{ Find the index of aVal. }
+function TList.IndexOf(const aVal: T): integer;
+var
+ loIdx, hiIdx, cnt, i: integer;
+begin
+ Result := - 1;
+ if (FSorted) then
+ begin
+ loIdx := 0;
+ hiIdx := (FCount - 1);
+ while (loIdx <= hiIdx) do
+ begin
+ cnt := ((loIdx + hiIdx) shr 1);
+ i := FCompare(FItems[cnt], aVal);
+ if (i < 0) then
+ loIdx := (cnt + 1)
+ else
+ begin
+ hiIdx := (cnt - 1);
+ if (i = 0) then
+ Exit(loIdx);
+ end;
+ end;
+ end
+ else
+ begin
+ for i := 0 to FCount - 1 do
+ if (FCompare(FItems[i], aVal) = 0) then
+ Exit(i);
+ end;
+end;
+
+{ Items getter. }
+function TList.GetT(const aIndex: integer): T;
+begin
+ if (aIndex < 0) or (aIndex >= FCount) then
+ raise EListIndexOutOfBounds.Create(Format('Index %d out of bounds %d.', [aIndex, FCount]));
+
+ Result := FItems[aIndex];
+end;
+
+{ Items setter. }
+procedure TList.SetT(const aIndex: integer; const Value: T);
+begin
+ if (aIndex < 0) or (aIndex >= FCount) then
+ raise EListIndexOutOfBounds.Create(Format('Index %d out of bounds %d.', [aIndex, FCount]));
+
+ FAssign(Value, FItems[aIndex]);
+end;
+
+end.
diff --git a/EvilWorks.System.CRT.pas b/EvilWorks.System.CRT.pas
new file mode 100644
index 0000000..d09492f
--- /dev/null
+++ b/EvilWorks.System.CRT.pas
@@ -0,0 +1,916 @@
+unit EvilWorks.System.CRT;
+
+{$IFDEF CONDITIONALEXPRESSIONS}
+{$IF CompilerVersion >= 17.0}{$DEFINE INLINES}{$IFEND}
+{$IF RTLVersion >= 14.0}{$DEFINE HASERROUTPUT}{$IFEND}
+{$ENDIF}
+
+interface
+
+uses
+ WinApi.Windows;
+
+const
+ // Background and foreground colors
+ Black = 0;
+ Blue = 1;
+ Green = 2;
+ Cyan = 3;
+ Red = 4;
+ Magenta = 5;
+ Brown = 6;
+ LightGray = 7;
+
+ // Foreground colors
+ DarkGray = 8;
+ LightBlue = 9;
+ LightGreen = 10;
+ LightCyan = 11;
+ LightRed = 12;
+ LightMagenta = 13;
+ Yellow = 14;
+ White = 15;
+
+ // Blink attribute, to be or-ed with background colors.
+ Blink = 128;
+
+ // Text modes:
+ BW40 = 0; // 40x25 B/W on Color Adapter
+ CO40 = 1; // 40x25 Color on Color Adapter
+ BW80 = 2; // 80x25 B/W on Color Adapter
+ CO80 = 3; // 80x25 Color on Color Adapter
+ Mono = 7; // 80x25 on Monochrome Adapter
+ Font8x8 = 256; // Add-in for ROM font
+
+ // Mode constants for 3.0 compatibility of original CRT unit }
+ C40 = CO40;
+ C80 = CO80;
+
+
+ // Turbo/Borland Pascal Crt routines:
+
+ // Waits for keypress and returns the key pressed. If the key is not an ASCII
+ // key, #0 is returned, and a successive ReadKey will give the extended key
+ // code of the key.
+function ReadKey: Char;
+
+// Checks whether a key was pressed.
+function KeyPressed: Boolean;
+
+// Puts the cursor at the given coordinates on the screen.
+procedure GotoXY(X, Y: Smallint);
+
+// Returns the current X position of the cursor.
+function WhereX: Integer;
+
+// Returns the current Y position of the cursor.
+function WhereY: Integer;
+
+// Sets text foreground color.
+procedure TextColor(Color: Byte); overload;
+
+// Gets text forground color.
+function TextColor: Byte; overload;
+
+// Sets text background color.
+procedure TextBackground(Color: Byte); overload;
+
+// Gets text background color.
+function TextBackground: Byte; overload;
+
+// Sets text mode.
+procedure TextMode(Mode: Word);
+
+// Sets text colors to low intensity
+procedure LowVideo;
+
+// Sets text colors to high intensity
+procedure HighVideo;
+
+// Sets text attribute to value at startup.
+procedure NormVideo;
+
+// Clears the entire screen, or, if a window is set, the entire window,
+// in the current background color.
+procedure ClrScr;
+
+// Clears until the end of the line, in the current background color.
+procedure ClrEol;
+
+// Inserts a line at the current cursor position.
+procedure InsLine;
+
+// Deletes the line at the current cursor position.
+procedure DelLine;
+
+// Sets a window, into which all successive output will go. You can reset the
+// window to full screen by calling Window with a zero or negative value
+// for Left.
+procedure Window(Left, Top, Right, Bottom: Integer);
+
+type
+ // Plays a sound at the given frequency (in Herz).
+ TSoundProc = procedure(Frequency: Smallint);
+
+ // Stops the sound started with Sound.
+ TNoSoundProc = procedure;
+
+ // Delays for the given amount of milliseconds, or as close as possible.
+ TDelayProc = procedure(Millisecs: Integer);
+
+ // Plays a sound at the given frequency (in Hz) and duration (in ms).
+ TBeepProc = procedure(Frequency, Duration: Smallint);
+
+var
+ Sound : TSoundProc;
+ NoSound: TNoSoundProc;
+ Delay : TDelayProc;
+ Beep : TBeepProc;
+
+ // Additional routines:
+
+function ScreenWidth: Smallint;
+function ScreenHeight: Smallint;
+function BufferWidth: Smallint;
+function BufferHeight: Smallint;
+
+var
+ TextWindow : TSmallRect;
+ TextAttr : Byte;
+ DefaultAttr : Byte;
+ ScreenMode : Byte;
+ BufferSize : TCoord;
+ ScreenSize : TCoord;
+ StdIn, StdOut: THandle;
+ StdErr : THandle;
+ LastMode : Word;
+ WindMin : Word;
+ WindMax : Word;
+ CheckBreak : Boolean;
+
+implementation
+
+uses SysUtils;
+
+type
+ PKey = ^TKey;
+
+ TKey = record
+ KeyCode: Smallint;
+ Normal: Smallint;
+ Shift: Smallint;
+ Ctrl: Smallint;
+ Alt: Smallint;
+ end;
+
+const
+ CKeys: array [0 .. 88] of TKey = (
+ (KeyCode: VK_BACK; Normal: $8; Shift: $8; Ctrl: $7F; Alt: $10E;),
+ (KeyCode: VK_TAB; Normal: $9; Shift: $10F; Ctrl: $194; Alt: $1A5;),
+ (KeyCode: VK_RETURN; Normal: $D; Shift: $D; Ctrl: $A; Alt: $1A6),
+ (KeyCode: VK_ESCAPE; Normal: $1B; Shift: $1B; Ctrl: $1B; Alt: $101),
+ (KeyCode: VK_SPACE; Normal: $20; Shift: $20; Ctrl: $103; Alt: $20),
+ (KeyCode: Ord('0'); Normal: Ord('0'); Shift: Ord(')'); Ctrl: - 1; Alt: $181),
+ (KeyCode: Ord('1'); Normal: Ord('1'); Shift: Ord('!'); Ctrl: - 1; Alt: $178),
+ (KeyCode: Ord('2'); Normal: Ord('2'); Shift: Ord('@'); Ctrl: $103; Alt: $179),
+ (KeyCode: Ord('3'); Normal: Ord('3'); Shift: Ord('#'); Ctrl: - 1; Alt: $17A),
+ (KeyCode: Ord('4'); Normal: Ord('4'); Shift: Ord('$'); Ctrl: - 1; Alt: $17B),
+ (KeyCode: Ord('5'); Normal: Ord('5'); Shift: Ord('%'); Ctrl: - 1; Alt: $17C),
+ (KeyCode: Ord('6'); Normal: Ord('6'); Shift: Ord('^'); Ctrl: $1E; Alt: $17D),
+ (KeyCode: Ord('7'); Normal: Ord('7'); Shift: Ord('&'); Ctrl: - 1; Alt: $17E),
+ (KeyCode: Ord('8'); Normal: Ord('8'); Shift: Ord('*'); Ctrl: - 1; Alt: $17F),
+ (KeyCode: Ord('9'); Normal: Ord('9'); Shift: Ord('('); Ctrl: - 1; Alt: $180),
+ (KeyCode: Ord('A'); Normal: Ord('a'); Shift: Ord('A'); Ctrl: $1; Alt: $11E),
+ (KeyCode: Ord('B'); Normal: Ord('b'); Shift: Ord('B'); Ctrl: $2; Alt: $130),
+ (KeyCode: Ord('C'); Normal: Ord('c'); Shift: Ord('C'); Ctrl: $3; Alt: $12E),
+ (KeyCode: Ord('D'); Normal: Ord('d'); Shift: Ord('D'); Ctrl: $4; Alt: $120),
+ (KeyCode: Ord('E'); Normal: Ord('e'); Shift: Ord('E'); Ctrl: $5; Alt: $112),
+ (KeyCode: Ord('F'); Normal: Ord('f'); Shift: Ord('F'); Ctrl: $6; Alt: $121),
+ (KeyCode: Ord('G'); Normal: Ord('g'); Shift: Ord('G'); Ctrl: $7; Alt: $122),
+ (KeyCode: Ord('H'); Normal: Ord('h'); Shift: Ord('H'); Ctrl: $8; Alt: $123),
+ (KeyCode: Ord('I'); Normal: Ord('i'); Shift: Ord('I'); Ctrl: $9; Alt: $117),
+ (KeyCode: Ord('J'); Normal: Ord('j'); Shift: Ord('J'); Ctrl: $A; Alt: $124),
+ (KeyCode: Ord('K'); Normal: Ord('k'); Shift: Ord('K'); Ctrl: $B; Alt: $125),
+ (KeyCode: Ord('L'); Normal: Ord('l'); Shift: Ord('L'); Ctrl: $C; Alt: $126),
+ (KeyCode: Ord('M'); Normal: Ord('m'); Shift: Ord('M'); Ctrl: $D; Alt: $132),
+ (KeyCode: Ord('N'); Normal: Ord('n'); Shift: Ord('N'); Ctrl: $E; Alt: $131),
+ (KeyCode: Ord('O'); Normal: Ord('o'); Shift: Ord('O'); Ctrl: $F; Alt: $118),
+ (KeyCode: Ord('P'); Normal: Ord('p'); Shift: Ord('P'); Ctrl: $10; Alt: $119),
+ (KeyCode: Ord('Q'); Normal: Ord('q'); Shift: Ord('Q'); Ctrl: $11; Alt: $110),
+ (KeyCode: Ord('R'); Normal: Ord('r'); Shift: Ord('R'); Ctrl: $12; Alt: $113),
+ (KeyCode: Ord('S'); Normal: Ord('s'); Shift: Ord('S'); Ctrl: $13; Alt: $11F),
+ (KeyCode: Ord('T'); Normal: Ord('t'); Shift: Ord('T'); Ctrl: $14; Alt: $114),
+ (KeyCode: Ord('U'); Normal: Ord('u'); Shift: Ord('U'); Ctrl: $15; Alt: $116),
+ (KeyCode: Ord('V'); Normal: Ord('v'); Shift: Ord('V'); Ctrl: $16; Alt: $12F),
+ (KeyCode: Ord('W'); Normal: Ord('w'); Shift: Ord('W'); Ctrl: $17; Alt: $111),
+ (KeyCode: Ord('X'); Normal: Ord('x'); Shift: Ord('X'); Ctrl: $18; Alt: $12D),
+ (KeyCode: Ord('Y'); Normal: Ord('y'); Shift: Ord('Y'); Ctrl: $19; Alt: $115),
+ (KeyCode: Ord('Z'); Normal: Ord('z'); Shift: Ord('Z'); Ctrl: $1A; Alt: $12C),
+ (KeyCode: VK_PRIOR; Normal: $149; Shift: $149; Ctrl: $184; Alt: $199),
+ (KeyCode: VK_NEXT; Normal: $151; Shift: $151; Ctrl: $176; Alt: $1A1),
+ (KeyCode: VK_END; Normal: $14F; Shift: $14F; Ctrl: $175; Alt: $19F),
+ (KeyCode: VK_HOME; Normal: $147; Shift: $147; Ctrl: $177; Alt: $197),
+ (KeyCode: VK_LEFT; Normal: $14B; Shift: $14B; Ctrl: $173; Alt: $19B),
+ (KeyCode: VK_UP; Normal: $148; Shift: $148; Ctrl: $18D; Alt: $198),
+ (KeyCode: VK_RIGHT; Normal: $14D; Shift: $14D; Ctrl: $174; Alt: $19D),
+ (KeyCode: VK_DOWN; Normal: $150; Shift: $150; Ctrl: $191; Alt: $1A0),
+ (KeyCode: VK_INSERT; Normal: $152; Shift: $152; Ctrl: $192; Alt: $1A2),
+ (KeyCode: VK_DELETE; Normal: $153; Shift: $153; Ctrl: $193; Alt: $1A3),
+ (KeyCode: VK_NUMPAD0; Normal: Ord('0'); Shift: $152; Ctrl: $192; Alt: - 1),
+ (KeyCode: VK_NUMPAD1; Normal: Ord('1'); Shift: $14F; Ctrl: $175; Alt: - 1),
+ (KeyCode: VK_NUMPAD2; Normal: Ord('2'); Shift: $150; Ctrl: $191; Alt: - 1),
+ (KeyCode: VK_NUMPAD3; Normal: Ord('3'); Shift: $151; Ctrl: $176; Alt: - 1),
+ (KeyCode: VK_NUMPAD4; Normal: Ord('4'); Shift: $14B; Ctrl: $173; Alt: - 1),
+ (KeyCode: VK_NUMPAD5; Normal: Ord('5'); Shift: $14C; Ctrl: $18F; Alt: - 1),
+ (KeyCode: VK_NUMPAD6; Normal: Ord('6'); Shift: $14D; Ctrl: $174; Alt: - 1),
+ (KeyCode: VK_NUMPAD7; Normal: Ord('7'); Shift: $147; Ctrl: $177; Alt: - 1),
+ (KeyCode: VK_NUMPAD8; Normal: Ord('8'); Shift: $148; Ctrl: $18D; Alt: - 1),
+ (KeyCode: VK_NUMPAD9; Normal: Ord('9'); Shift: $149; Ctrl: $184; Alt: - 1),
+ (KeyCode: VK_MULTIPLY; Normal: Ord('*'); Shift: Ord('*'); Ctrl: $196; Alt: $137),
+ (KeyCode: VK_ADD; Normal: Ord('+'); Shift: Ord('+'); Ctrl: $190; Alt: $14E),
+ (KeyCode: VK_SUBTRACT; Normal: Ord('-'); Shift: Ord('-'); Ctrl: $18E; Alt: $14A),
+ (KeyCode: VK_DECIMAL; Normal: Ord('.'); Shift: Ord('.'); Ctrl: $153; Alt: $193),
+ (KeyCode: VK_DIVIDE; Normal: Ord('/'); Shift: Ord('/'); Ctrl: $195; Alt: $1A4),
+ (KeyCode: VK_F1; Normal: $13B; Shift: $154; Ctrl: $15E; Alt: $168),
+ (KeyCode: VK_F2; Normal: $13C; Shift: $155; Ctrl: $15F; Alt: $169),
+ (KeyCode: VK_F3; Normal: $13D; Shift: $156; Ctrl: $160; Alt: $16A),
+ (KeyCode: VK_F4; Normal: $13E; Shift: $157; Ctrl: $161; Alt: $16B),
+ (KeyCode: VK_F5; Normal: $13F; Shift: $158; Ctrl: $162; Alt: $16C),
+ (KeyCode: VK_F6; Normal: $140; Shift: $159; Ctrl: $163; Alt: $16D),
+ (KeyCode: VK_F7; Normal: $141; Shift: $15A; Ctrl: $164; Alt: $16E),
+ (KeyCode: VK_F8; Normal: $142; Shift: $15B; Ctrl: $165; Alt: $16F),
+ (KeyCode: VK_F9; Normal: $143; Shift: $15C; Ctrl: $166; Alt: $170),
+ (KeyCode: VK_F10; Normal: $144; Shift: $15D; Ctrl: $167; Alt: $171),
+ (KeyCode: VK_F11; Normal: $185; Shift: $187; Ctrl: $189; Alt: $18B),
+ (KeyCode: VK_F12; Normal: $186; Shift: $188; Ctrl: $18A; Alt: $18C),
+ (KeyCode: $DC; Normal: Ord('\'); Shift: Ord('|'); Ctrl: $1C; Alt: $12B),
+ (KeyCode: $BF; Normal: Ord('/'); Shift: Ord('?'); Ctrl: - 1; Alt: $135),
+ (KeyCode: $BD; Normal: Ord('-'); Shift: Ord('_'); Ctrl: $1F; Alt: $182),
+ (KeyCode: $BB; Normal: Ord('='); Shift: Ord('+'); Ctrl: - 1; Alt: $183),
+ (KeyCode: $DB; Normal: Ord('['); Shift: Ord('{'); Ctrl: $1B; Alt: $11A),
+ (KeyCode: $DD; Normal: Ord(']'); Shift: Ord('}'); Ctrl: $1D; Alt: $11B),
+ (KeyCode: $BA; Normal: Ord(';'); Shift: Ord(':'); Ctrl: - 1; Alt: $127),
+ (KeyCode: $DE; Normal: Ord(''''); Shift: Ord('"'); Ctrl: - 1; Alt: $128),
+ (KeyCode: $BC; Normal: Ord(','); Shift: Ord('<'); Ctrl: - 1; Alt: $133),
+ (KeyCode: $BE; Normal: Ord('.'); Shift: Ord('>'); Ctrl: - 1; Alt: $134),
+ (KeyCode: $C0; Normal: Ord('`'); Shift: Ord('~'); Ctrl: - 1; Alt: $129)
+ );
+
+var
+ ExtendedChar: Char = #0;
+
+function FindKeyCode(KeyCode: Smallint): PKey; {$IFDEF INLINES}inline; {$ENDIF}
+var
+ I: Integer;
+begin
+ for I := 0 to high(CKeys) do
+ if CKeys[I].KeyCode = KeyCode then
+ begin
+ Result := @CKeys[I];
+ Exit;
+ end;
+ Result := nil;
+end;
+
+// This has a complexity of 11, because of the if else ladder.
+// That bugs me a bit. Looking for something more elegant.
+function TranslateKey(const Rec: TInputRecord; State: Integer; Key: PKey; KeyCode: Integer): Smallint;
+begin
+ if State and (RIGHT_ALT_PRESSED or LEFT_ALT_PRESSED) <> 0 then
+ Result := Key^.Alt
+ else if State and (RIGHT_CTRL_PRESSED or LEFT_CTRL_PRESSED) <> 0 then
+ Result := Key^.Ctrl
+ else if State and SHIFT_PRESSED <> 0 then
+ Result := Key^.Shift
+ else if KeyCode in [Ord('A') .. Ord('Z')] then
+ Result := Ord(Rec.Event.KeyEvent.AsciiChar)
+ else
+ Result := Key^.Normal;
+end;
+
+function ConvertKey(const Rec: TInputRecord; Key: PKey): Smallint;
+{$IFDEF INLINES}inline; {$ENDIF}
+begin
+ if Assigned(Key) then
+ Result := TranslateKey(Rec, Rec.Event.KeyEvent.dwControlKeyState,
+ Key, Rec.Event.KeyEvent.wVirtualKeyCode)
+ else
+ Result := - 1
+end;
+
+function ReadKey: Char;
+var
+ InputRec: TInputRecord;
+ NumRead : Cardinal;
+ KeyMode : DWORD;
+ KeyCode : Smallint;
+begin
+ if ExtendedChar <> #0 then
+ begin
+ Result := ExtendedChar;
+ ExtendedChar := #0;
+ Exit;
+ end
+ else
+ begin
+ Result := #$FF;
+ GetConsoleMode(StdIn, KeyMode);
+ SetConsoleMode(StdIn, 0);
+ repeat
+ ReadConsoleInput(StdIn, InputRec, 1, NumRead);
+ if (InputRec.EventType and KEY_EVENT <> 0) and
+ InputRec.Event.KeyEvent.bKeyDown then
+ begin
+ if InputRec.Event.KeyEvent.AsciiChar <> #0 then
+ begin
+ // From Delphi 2009 on, Result is WideChar
+ Result := Chr(Ord(InputRec.Event.KeyEvent.AsciiChar));
+ Break;
+ end;
+ KeyCode := ConvertKey(InputRec,
+ FindKeyCode(InputRec.Event.KeyEvent.wVirtualKeyCode));
+ if KeyCode > $FF then
+ begin
+ ExtendedChar := Chr(KeyCode and $FF);
+ Result := #0;
+ Break;
+ end;
+ end;
+ until False;
+ SetConsoleMode(StdIn, KeyMode);
+ end;
+end;
+
+function KeyPressed: Boolean;
+var
+ InputRecArray: array of TInputRecord;
+ NumRead : DWORD;
+ NumEvents : DWORD;
+ I : Integer;
+ KeyCode : Word;
+begin
+ Result := False;
+ GetNumberOfConsoleInputEvents(StdIn, NumEvents);
+ if NumEvents = 0 then
+ Exit;
+ SetLength(InputRecArray, NumEvents);
+ PeekConsoleInput(StdIn, InputRecArray[0], NumEvents, NumRead);
+ for I := 0 to high(InputRecArray) do
+ begin
+ if (InputRecArray[I].EventType and KEY_EVENT <> 0) and
+ InputRecArray[I].Event.KeyEvent.bKeyDown then
+ begin
+ KeyCode := InputRecArray[I].Event.KeyEvent.wVirtualKeyCode;
+ if not (KeyCode in [VK_SHIFT, VK_MENU, VK_CONTROL]) then
+ begin
+ if ConvertKey(InputRecArray[I], FindKeyCode(KeyCode)) <> - 1 then
+ begin
+ Result := True;
+ Exit;
+ end;
+ end;
+ end;
+ end;
+end;
+
+procedure TextColor(Color: Byte);
+begin
+ LastMode := TextAttr;
+ TextAttr := (TextAttr and $F0) or (Color and $0F);
+ SetConsoleTextAttribute(StdOut, TextAttr);
+end;
+
+procedure TextBackground(Color: Byte);
+begin
+ LastMode := TextAttr;
+ TextAttr := (TextAttr and $0F) or ((Color shl 4) and $F0);
+ SetConsoleTextAttribute(StdOut, TextAttr);
+end;
+
+procedure LowVideo;
+begin
+ LastMode := TextAttr;
+ TextAttr := TextAttr and $F7;
+ SetConsoleTextAttribute(StdOut, TextAttr);
+end;
+
+procedure HighVideo;
+begin
+ LastMode := TextAttr;
+ TextAttr := TextAttr or $08;
+ SetConsoleTextAttribute(StdOut, TextAttr);
+end;
+
+procedure NormVideo;
+begin
+ TextAttr := DefaultAttr;
+ SetConsoleTextAttribute(StdOut, TextAttr);
+end;
+
+// The following functions are independent of TextWindow.
+
+function GetCursorX: Integer; {$IFDEF INLINES}inline; {$ENDIF}
+var
+ BufferInfo: TConsoleScreenBufferInfo;
+begin
+ GetConsoleSCreenBufferInfo(StdOut, BufferInfo);
+ Result := BufferInfo.dwCursorPosition.X;
+end;
+
+function GetCursorY: Integer; {$IFDEF INLINES}inline; {$ENDIF}
+var
+ BufferInfo: TConsoleScreenBufferInfo;
+begin
+ GetConsoleSCreenBufferInfo(StdOut, BufferInfo);
+ Result := BufferInfo.dwCursorPosition.Y;
+end;
+
+procedure SetCursorPos(X, Y: Smallint);
+var
+ NewPos: TCoord;
+begin
+ NewPos.X := X;
+ NewPos.Y := Y;
+ SetConsoleCursorPosition(StdOut, NewPos);
+end;
+
+// The following functions are relative to TextWindow.
+
+procedure ClrScr;
+var
+ StartPos : TCoord;
+ Len, NumWritten: DWORD;
+ I : Integer;
+begin
+ if (TextWindow.Left = 0) and (TextWindow.Top = 0) and
+ (TextWindow.Right = BufferSize.X - 1) and
+ (TextWindow.Bottom = BufferSize.Y - 1) then
+ begin
+ StartPos.X := 0;
+ StartPos.Y := 0;
+ Len := BufferSize.X * BufferSize.Y;
+ FillConsoleOutputCharacterA(StdOut, ' ', Len, StartPos, NumWritten);
+ FillConsoleOutputAttribute(StdOut, TextAttr, Len, StartPos, NumWritten);
+ if NumWritten < Len then
+ begin
+ ScreenSize.X := ScreenWidth;
+ ScreenSize.Y := ScreenHeight;
+ end;
+ end
+ else
+ begin
+ Len := TextWindow.Right - TextWindow.Left + 1;
+ StartPos.X := TextWindow.Left;
+ for I := TextWindow.Top to TextWindow.Bottom do
+ begin
+ StartPos.Y := I;
+ FillConsoleOutputCharacterA(StdOut, ' ', Len, StartPos, NumWritten);
+ FillConsoleOutputAttribute(StdOut, TextAttr, Len, StartPos, NumWritten);
+ end;
+ end;
+ GotoXY(1, 1);
+end;
+
+procedure GotoXY(X, Y: Smallint);
+begin
+ Inc(X, TextWindow.Left - 1);
+ Inc(Y, TextWindow.Top - 1);
+ if (X >= TextWindow.Left) and (X <= TextWindow.Right) and
+ (Y >= TextWindow.Top) and (Y <= TextWindow.Bottom) then
+ SetCursorPos(X, Y);
+end;
+
+procedure ClrEol;
+var
+ Len : Integer;
+ Pos : TCoord;
+ NumWritten: DWORD;
+begin
+ Len := TextWindow.Right - GetCursorX + 1;
+ Pos.X := GetCursorX;
+ Pos.Y := GetCursorY;
+ FillConsoleOutputCharacterA(StdOut, ' ', Len, Pos, NumWritten);
+ FillConsoleOutputAttribute(StdOut, TextAttr, Len, Pos, NumWritten);
+end;
+
+procedure Scroll(Left, Top, Right, Bottom: Integer; Distance: Integer = 0);
+var
+ Rect : TSmallRect;
+ Fill : TCharInfo;
+ NewPos: TCoord;
+begin
+ Fill.AsciiChar := ' ';
+ Fill.Attributes := TextAttr;
+ if Distance = 0 then
+ Distance := Bottom - Top + 1;
+ Rect.Left := Left;
+ Rect.Right := Right;
+ Rect.Top := Top;
+ Rect.Bottom := Bottom;
+ NewPos.X := Left;
+ NewPos.Y := Top + Distance;
+ ScrollConsoleScreenBufferA(StdOut, Rect, @Rect, NewPos, Fill);
+end;
+
+procedure InsLine;
+begin
+ Scroll(TextWindow.Left, GetCursorY,
+ TextWindow.Right, TextWindow.Bottom, 1);
+end;
+
+procedure DelLine;
+begin
+ Scroll(TextWindow.Left, GetCursorY,
+ TextWindow.Right, TextWindow.Bottom, - 1);
+end;
+
+function Validate(X1, Y1, X2, Y2: Integer): Boolean;
+{$IFDEF INLINES}inline; {$ENDIF}
+begin
+ Result := (X1 < X2) and (Y1 < Y2) and
+ (X1 >= 0) and (X2 < BufferSize.X) and
+ (Y1 >= 0) and (Y2 < BufferSize.Y);
+end;
+
+procedure WriteText(Line: PAnsiChar; Len: Integer);
+var
+ NumWritten: DWORD;
+begin
+ SetConsoleTextAttribute(StdOut, TextAttr);
+ WriteConsoleA(StdOut, Line, Len, NumWritten, nil);
+end;
+
+// Replacement for TTextRec.InOutFunc and TTextRec.FlushFunc for the Output
+// and ErrOutput pseudo-textfiles.
+// This is generally only used if a text window is set, otherwise this is
+// handled by the runtime library.
+function NewTextOut(var T: TTextRec): Integer;
+var
+ ReadPtr, WritePtr: PAnsiChar;
+ Line : AnsiString;
+ DistanceToEdge : Integer;
+
+ // Moves cursor to start of line, updates DistanceToEdge.
+ procedure CarriageReturn;
+ begin
+ SetCursorPos(TextWindow.Left, GetCursorY);
+ DistanceToEdge := TextWindow.Right - TextWindow.Left + 1;
+ end;
+
+// Moves cursor down one line. If necessary, scrolls window.
+ procedure LineFeed; {$IFDEF INLINES}inline; {$ENDIF}
+ begin
+ if GetCursorY < TextWindow.Bottom then
+ SetCursorPos(GetCursorX, GetCursorY + 1)
+ else
+ Scroll(TextWindow.Left, TextWindow.Top, TextWindow.Right,
+ TextWindow.Bottom, - 1);
+ end;
+
+// Store one char in write buffer.
+ procedure CharToWriteBuffer(C: AnsiChar);
+ begin
+ WritePtr^ := C;
+ Inc(WritePtr);
+ Dec(DistanceToEdge);
+ end;
+
+// True if at right edge of window.
+ function WriteLine: Boolean;
+ begin
+ WritePtr^ := #0;
+ WriteText(PAnsiChar(Line), WritePtr - PAnsiChar(Line));
+ Result := DistanceToEdge = 0;
+ WritePtr := PAnsiChar(Line);
+ DistanceToEdge := TextWindow.Right - TextWindow.Left + 1;
+ end;
+
+// Converts tabs to spaces, since WriteConsole will do its own tabbing when
+// it encounters a #9, which is of course independent of this unit's
+// TextWindow settings.
+ procedure ProcessTab;
+ var
+ Num, I: Integer;
+ begin
+ Num := 8 - (WritePtr - PAnsiChar(Line)) mod 8;
+ if Num > DistanceToEdge then
+ Num := DistanceToEdge;
+ for I := 1 to Num do
+ CharToWriteBuffer(' ');
+ end;
+
+begin
+ SetLength(Line, BufferSize.X); // Line only contains one line of windowed text.
+ WritePtr := PAnsiChar(Line);
+ ReadPtr := T.BufPtr;
+ DistanceToEdge := TextWindow.Right - GetCursorX + 1;
+ while T.BufPos > 0 do
+ begin
+ while (T.BufPos > 0) and (DistanceToEdge > 0) do
+ begin
+ case ReadPtr^ of
+ #7:
+ Beep(800, 200); // this is what my internal speaker uses.
+ #8:
+ begin
+ Dec(WritePtr);
+ Inc(DistanceToEdge);
+ end;
+ #9:
+ ProcessTab;
+ // LineFeed is not just a line feed, it takes the function of #13#10
+ #10:
+ begin
+ WriteLine;
+ CarriageReturn;
+ LineFeed;
+ end;
+ #13:
+ begin
+ WriteLine;
+ CarriageReturn;
+ end;
+ else
+ CharToWriteBuffer(ReadPtr^);
+ end;
+ Inc(ReadPtr);
+ Dec(T.BufPos);
+ end;
+ if WriteLine then
+ begin
+ CarriageReturn;
+ // If TexWindow.Right is at the edge of the screen, WriteConsole will
+ // already do a linefeed.
+ if TextWindow.Right <> ScreenWidth - 1 then
+ LineFeed;
+ end;
+ end;
+ Result := 0;
+end;
+
+var
+ OldInOutFunc: Pointer;
+ OldFlushFunc: Pointer;
+
+procedure Window(Left, Top, Right, Bottom: Integer);
+begin
+ Dec(Left);
+ Dec(Top);
+ Dec(Right);
+ Dec(Bottom);
+ if Validate(Left, Top, Right, Bottom) then
+ begin
+ TextWindow.Left := Left;
+ TextWindow.Top := Top;
+ TextWindow.Right := Right;
+ TextWindow.Bottom := Bottom;
+ if (Left > 0) or (Top > 0) or
+ (Right < BufferSize.X - 1) or (Bottom < BufferSize.Y - 1) then
+ // Text must be contained in window
+ begin
+ OldInOutFunc := TTextRec(Output).InOutFunc;
+ OldFlushFunc := TTextRec(Output).FlushFunc;
+ TTextRec(Output).InOutFunc := @NewTextOut;
+ TTextRec(Output).FlushFunc := @NewTextOut;
+ SetCursorPos(Left, Top);
+ end;
+ end
+ else
+ begin
+ TextWindow.Left := 0;
+ TextWindow.Right := BufferSize.X - 1;
+ TextWindow.Top := 0;
+ TextWindow.Bottom := BufferSize.Y - 1;
+ SetCursorPos(0, 0);
+ if Assigned(OldInOutFunc) then
+ begin
+ TTextRec(Output).InOutFunc := OldInOutFunc;
+ OldInOutFunc := nil;
+ end;
+ if Assigned(OldFlushFunc) then
+ begin
+ TTextRec(Output).FlushFunc := OldFlushFunc;
+ OldFlushFunc := nil;
+ end;
+ end;
+ WindMin := (TextWindow.Left and $FF) or (TextWindow.Top and $FF) shl 8;
+ WindMax := (TextWindow.Right and $FF) or (TextWindow.Bottom and $FF) shl 8;
+end;
+
+procedure HardwareSound(Frequency: Smallint);
+asm
+ CMP AX,37
+ JB @@1
+ MOV CX,AX
+ MOV AL,$B6
+ OUT $43,AL
+ MOV AX,$3540
+ MOV DX,$0012
+ DIV CX
+ OUT $42,AL
+ MOV AL,AH
+ OUT $42,AL
+ MOV AL,3
+ OUT $61,AL
+@@1:
+end;
+
+procedure HardwareNoSound;
+asm
+ MOV AL,0
+ OUT $61,AL
+end;
+
+procedure HardwareDelay(Millisecs: Integer);
+begin
+ Sleep(Millisecs);
+end;
+
+procedure HardwareBeep(Frequency, Duration: Smallint);
+begin
+ Sound(Frequency);
+ Delay(Duration);
+ NoSound;
+end;
+
+type
+ TSoundState = (ssPending, ssPlaying, ssFreed);
+
+var
+ CurrentFrequency: Integer;
+ SoundState : TSoundState;
+
+ // On Windows NT and later, direct port access is prohibited, so there is
+ // no way to use HardwareSound and HardwareNoSound.
+ //
+ // Since probably every note played by Sound will be delimited by some kind
+ // of Delay, the playing of the note is deferred to Delay. Sound only stores
+ // the frequency and sets the SoundState to ssPending. Delay now knows both
+ // parameters, and can use Windows.Beep.
+ //
+ // Note that such code is not reentrant.
+
+procedure SoftwareSound(Frequency: Smallint);
+begin
+ // $123540 div Frequency must be <= $7FFF, so Frequency must be >= 37.
+ if Frequency >= 37 then
+ begin
+ CurrentFrequency := Frequency;
+ SoundState := ssPending;
+ end;
+end;
+
+procedure SoftwareDelay(Millisecs: Integer);
+begin
+ if SoundState = ssPending then
+ begin
+ SoundState := ssPlaying;
+ Beep(CurrentFrequency, Millisecs);
+ SoundState := ssFreed;
+ end
+ else
+ Sleep(Millisecs);
+end;
+
+procedure SoftwareBeep(Frequency, Duration: Smallint);
+begin
+ if Frequency >= 37 then
+ begin
+ SoundState := ssPlaying;
+ Beep(Frequency, Duration);
+ SoundState := ssFreed;
+ end;
+end;
+
+procedure SoftwareNoSound;
+begin
+ Beep(CurrentFrequency, 0);
+ SoundState := ssFreed;
+end;
+
+function WhereX: Integer;
+begin
+ Result := GetCursorX - TextWindow.Left + 1;
+end;
+
+function WhereY: Integer;
+begin
+ Result := GetCursorY - TextWindow.Top + 1;
+end;
+
+procedure GetScreenSizes(var Width, Height: Smallint);
+var
+ BufferInfo: TConsoleScreenBufferInfo;
+begin
+ GetConsoleSCreenBufferInfo(StdOut, BufferInfo);
+ Width := BufferInfo.srWindow.Right - BufferInfo.srWindow.Left + 1;
+ Height := BufferInfo.srWindow.Bottom - BufferInfo.srWindow.Top + 1;
+end;
+
+function ScreenWidth: Smallint;
+var
+ Height: Smallint;
+begin
+ GetScreenSizes(Result, Height);
+end;
+
+function ScreenHeight: Smallint;
+var
+ Width: Smallint;
+begin
+ GetScreenSizes(Width, Result);
+end;
+
+procedure GetBufferSizes(var Width, Height: Smallint);
+var
+ BufferInfo: TConsoleScreenBufferInfo;
+begin
+ GetConsoleSCreenBufferInfo(StdOut, BufferInfo);
+ Width := BufferInfo.dwSize.X;
+ Height := BufferInfo.dwSize.Y;
+end;
+
+function BufferWidth: Smallint;
+var
+ Height: Smallint;
+begin
+ GetBufferSizes(Result, Height);
+end;
+
+function BufferHeight: Smallint;
+var
+ Width: Smallint;
+begin
+ GetBufferSizes(Width, Result);
+end;
+
+function TextColor: Byte;
+begin
+ Result := TextAttr and $0F;
+end;
+
+function TextBackground: Byte;
+begin
+ Result := (TextAttr and $F0) shr 4;
+end;
+
+procedure TextMode(Mode: Word);
+begin
+ Window(0, 0, 0, 0);
+ NormVideo;
+end;
+
+procedure InitScreenMode;
+var
+ BufferInfo: TConsoleScreenBufferInfo;
+begin
+ Reset(Input);
+ Rewrite(Output);
+ StdIn := TTextRec(Input).Handle;
+ StdOut := TTextRec(Output).Handle;
+{$IFDEF HASERROUTPUT}
+ Rewrite(ErrOutput);
+ StdErr := TTextRec(ErrOutput).Handle;
+{$ELSE}
+ StdErr := GetStdHandle(STD_ERROR_HANDLE);
+{$ENDIF}
+ if not GetConsoleSCreenBufferInfo(StdOut, BufferInfo) then
+ begin
+ SetInOutRes(GetLastError);
+ Exit;
+ end;
+ TextWindow.Left := 0;
+ TextWindow.Top := 0;
+ TextWindow.Right := BufferInfo.dwSize.X - 1;
+ TextWindow.Bottom := BufferInfo.dwSize.Y - 1;
+ TextAttr := BufferInfo.wAttributes and $FF;
+ DefaultAttr := TextAttr;
+ BufferSize := BufferInfo.dwSize;
+ ScreenSize.X := BufferInfo.srWindow.Right - BufferInfo.srWindow.Left + 1;
+ ScreenSize.Y := BufferInfo.srWindow.Bottom - BufferInfo.srWindow.Top + 1;
+ WindMin := 0;
+ WindMax := (ScreenSize.X and $FF) or (ScreenSize.Y and $FF) shl 8;
+ LastMode := CO80;
+ OldInOutFunc := nil;
+ OldFlushFunc := nil;
+ if Win32Platform = VER_PLATFORM_WIN32_NT then
+ begin
+ Sound := SoftwareSound;
+ NoSound := SoftwareNoSound;
+ Delay := SoftwareDelay;
+ Beep := SoftwareBeep;
+ end
+ else
+ begin
+ Sound := HardwareSound;
+ NoSound := HardwareNoSound;
+ Delay := HardwareDelay;
+ Beep := HardwareBeep;
+ end;
+end;
+
+initialization
+
+InitScreenMode;
+
+end.
diff --git a/EvilWorks.System.CommandLine.pas b/EvilWorks.System.CommandLine.pas
new file mode 100644
index 0000000..879cb82
--- /dev/null
+++ b/EvilWorks.System.CommandLine.pas
@@ -0,0 +1,126 @@
+unit EvilWorks.System.CommandLine;
+
+interface
+
+uses
+ Winapi.Windows,
+ EvilWorks.System.StrUtils;
+
+type
+ { TCmdLine }
+ { Gets current command line and splits it into Tokens. Switch prefixes ARE "-" OR "/". }
+ { Call Parse to split, Result indicates success. Double quotes around stuff mean ONE token. }
+ { -switch1 param1 -switch2 "param 2" -"switch 3" param3 -switch4 -"switch 5" ... }
+ TCmdLine = record
+ public type
+ PCmdLineItem = ^TCmdLineItem;
+ TCmdLineItem = record
+ Switch: string;
+ Param: string;
+ end;
+ private
+ FApp : string;
+ FItems: array of TCmdLineItem;
+ function GetItem(aIndex: integer): TCmdLineItem;
+ function GetCount: integer;
+ function GetSwitch(const aName: string): TCmdLineItem;
+ public
+ function Parse: boolean;
+
+ function SwitchExists(const aSwitch: string): boolean;
+ function SwitchIs(const aIndex: integer; const aText: string): boolean;
+
+ property App: string read FApp; // First item in command line, application path
+ property Items[aIndex: integer]: TCmdLineItem read GetItem; default;
+ property Switch[const aName: string]: TCmdLineItem read GetSwitch;
+ property Count: integer read GetCount; // Does not count first param (app path)
+ end;
+
+implementation
+
+{ TCmdLine }
+
+function TCmdLine.Parse: boolean;
+var
+ tokens: TTokens;
+ item : PCmdLineItem;
+ i : integer;
+begin
+ Result := False;
+
+ tokens := TextTokenize(GetCommandLine, CSpace, CDoubleQuote, [soCSSep, soQuoted, soCSQot]);
+ if (tokens.Count = 0) then
+ Exit;
+ FApp := tokens[0];
+ i := 1;
+ while (i < tokens.Count) do
+ begin
+ if (TextLeft(tokens[i], 1) = CMinus) or (TextLeft(tokens[i], 1) = CFrontSlash) then
+ begin
+ SetLength(FItems, Length(FItems) + 1);
+ item := @FItems[Length(FItems) - 1];
+ item^.Switch := TextUnquote(TextRight(tokens[i], Length(tokens[i]) - 1));
+ if (tokens[i + 1] <> CEmpty) then
+ begin
+ if (TextLeft(tokens[i + 1], 1) <> CMinus) and (TextLeft(tokens[i + 1], 1) <> CFrontSlash) then
+ begin
+ item^.Param := TextUnquote(tokens[i + 1]);
+ Inc(i, 2);
+ end
+ else
+ Inc(i, 1);
+ end
+ else
+ Break;
+ end
+ else
+ Exit;
+ end;
+ Result := True;
+end;
+
+function TCmdLine.SwitchExists(const aSwitch: string): boolean;
+var
+ i: integer;
+begin
+ Result := False;
+ for i := 0 to GetCount - 1 do
+ if (TextEquals(FItems[i].Switch, aSwitch)) then
+ Exit(True);
+end;
+
+function TCmdLine.SwitchIs(const aIndex: integer; const aText: string): boolean;
+begin
+ Result := TextEquals(GetItem(aIndex).Switch, aText);
+end;
+
+function TCmdLine.GetCount: integer;
+begin
+ Result := Length(FItems);
+end;
+
+function TCmdLine.GetItem(aIndex: integer): TCmdLineItem;
+begin
+ if (aIndex < 0) or (aIndex >= Count) then
+ begin
+ Result.Param := '';
+ Result.Switch := '';
+ end
+ else
+ Result := FItems[aIndex];
+end;
+
+function TCmdLine.GetSwitch(const aName: string): TCmdLineItem;
+var
+ i: integer;
+begin
+ for i := 0 to Count - 1 do
+ begin
+ if (TextEquals(FItems[i].Switch, aName)) then
+ Exit(FItems[i]);
+ end;
+ Result.Switch := '';
+ Result.Param := '';
+end;
+
+end.
diff --git a/EvilWorks.System.DateUtils.pas b/EvilWorks.System.DateUtils.pas
new file mode 100644
index 0000000..ad3b319
--- /dev/null
+++ b/EvilWorks.System.DateUtils.pas
@@ -0,0 +1,119 @@
+unit EvilWorks.System.DateUtils;
+
+interface
+
+uses
+ WinApi.Windows,
+ System.SysUtils,
+ System.DateUtils;
+
+function DateNowUTC: TDateTime;
+function DateTimeFromFileTime(aFileTime: TFileTime): TDateTime;
+function DateHTTPTimestamp: string;
+function DateTimeFromTwitterTimestamp(const aTimeStamp: string; var aDateTime: TDateTime): boolean;
+
+var
+ EnUsFormatSettings: TFormatSettings;
+
+implementation
+
+uses
+ EvilWorks.System.StrUtils;
+
+{ Now() equivalent returns time in UTC/GMT timezone. }
+function DateNowUTC: TDateTime;
+var
+ sysTime: TSystemTime;
+begin
+ GetSystemTime(sysTime);
+ Result := SystemTimeToDateTime(sysTime);
+end;
+
+{ Converts TFileTime to TDateTime. }
+function DateTimeFromFileTime(aFileTime: TFileTime): TDateTime;
+var
+ temp : TDateTime;
+ localFileTime : TFileTime;
+ localSystemTime: TSystemTime;
+begin
+ FileTimeToLocalFileTime(aFileTime, localFileTime);
+ FileTimeToSystemTime(localFileTime, localSystemTime);
+ TryEncodeDate(localSystemTime.wYear, localSystemTime.wMonth, localSystemTime.wDay, temp);
+ Result := temp;
+ TryEncodeTime(localSystemTime.wHour, localSystemTime.wMinute, localSystemTime.wSecond, localSystemTime.wMilliseconds, temp);
+ Result := Result + temp;
+end;
+
+{ Creates a HTTP timestamp. }
+function DateHTTPTimestamp: string;
+begin
+ Result := FormatDateTime('ddd, dd mmm yyyy hh:nn:ss', DateNowUTC, EnUsFormatSettings) + ' GMT';
+end;
+
+{ Converts Twitter's timestamp string to TDateTime. Don't look at the code when you look at the code. }
+function DateTimeFromTwitterTimestamp(const aTimeStamp: string; var aDateTime: TDateTime): boolean;
+var
+ tokens: TTokens;
+ eYear, eMonth, eDay, eHour, eMinute, eSecond: word;
+ eOffset, i: integer;
+begin
+ Result := False;
+ if (aTimeStamp = '') then
+ Exit;
+
+ tokens := TextTokenize(aTimeStamp);
+ if (tokens.Count <> 6) then
+ Exit;
+
+ eMonth := $FFFF;
+ for i := 1 to high(EnUsFormatSettings.ShortMonthNames) do
+ begin
+ if (SameText(tokens[1], EnUsFormatSettings.ShortMonthNames[i])) then
+ begin
+ eMonth := i;
+ Break;
+ end;
+ end;
+ if (eMonth = $FFFF) then
+ Exit;
+
+ eDay := TextToInt(tokens[2], $FFFF);
+ if (eday = $FFFF) then
+ Exit;
+
+ eOffset := TextToInt(tokens[4], MaxInt);
+ if (eOffset = maxInt) then
+ Exit;
+
+ eYear := TextToInt(tokens[5], $FFFF);
+ if (eYear = $FFFF) then
+ Exit;
+
+ tokens := TextTokenize(tokens[3], ':');
+ if (tokens.Count <> 3) then
+ Exit;
+
+ eHour := TextToInt(tokens[0], $FFFF);
+ if (eHour = $FFFF) then
+ Exit;
+
+ eMinute := TextToInt(tokens[1], $FFFF);
+ if (eMinute = $FFFF) then
+ Exit;
+
+ eSecond := TextToInt(tokens[2], $FFFF);
+ if (eSecond = $FFFF) then
+ Exit;
+
+ if (TryEncodeDateTime(eYear, eMonth, eDay, eHour, eMinute, eSecond, 0, aDateTime) = False) then
+ Exit;
+
+ aDateTime := IncHour(aDateTime, eOffset);
+ Result := True;
+end;
+
+initialization
+
+EnUsFormatSettings := TFormatSettings.Create('en-us');
+
+end.
diff --git a/EvilWorks.System.MsgApp.pas b/EvilWorks.System.MsgApp.pas
new file mode 100644
index 0000000..9569f50
--- /dev/null
+++ b/EvilWorks.System.MsgApp.pas
@@ -0,0 +1,48 @@
+unit EvilWorks.System.MsgApp;
+
+interface
+
+uses
+ System.Classes;
+
+type
+ { TMsgApp }
+ TMsgApp = class
+ private
+ procedure InitWindow;
+ procedure FinWindow;
+ public
+ constructor Create;
+ destructor Destroy; override;
+ end;
+
+implementation
+
+{ TMsgApp }
+
+constructor TMsgApp.Create;
+begin
+
+end;
+
+destructor TMsgApp.Destroy;
+begin
+
+ inherited;
+end;
+
+procedure TMsgApp.FinWindow;
+begin
+
+end;
+
+procedure TMsgApp.InitWindow;
+begin
+
+end;
+
+initialization
+
+finalization
+
+end.
diff --git a/EvilWorks.System.ProcessUtils.pas b/EvilWorks.System.ProcessUtils.pas
new file mode 100644
index 0000000..38e949d
--- /dev/null
+++ b/EvilWorks.System.ProcessUtils.pas
@@ -0,0 +1,229 @@
+unit EvilWorks.System.ProcessUtils;
+
+interface
+
+uses
+ WinApi.Windows,
+ WinApi.PsApi,
+ System.SysUtils;
+
+const
+{$EXTERNALSYM PROCESS_QUERY_LIMITED_INFORMATION}
+ PROCESS_QUERY_LIMITED_INFORMATION = $1000;
+
+{$EXTERNALSYM BELOW_NORMAL_PRIORITY_CLASS}
+ BELOW_NORMAL_PRIORITY_CLASS = $00004000;
+
+{$EXTERNALSYM ABOVE_NORMAL_PRIORITY_CLASS}
+ ABOVE_NORMAL_PRIORITY_CLASS = $00008000;
+
+type
+ TGetProcessImageFileName = function(hProcess: THandle; lpImageFileName: LPWSTR; nSize: DWORD): DWORD; stdcall;
+ TGetProcessImageFileNameA = function(hProcess: THandle; lpImageFileName: LPSTR; nSize: DWORD): DWORD; stdcall;
+ TGetProcessImageFileNameW = function(hProcess: THandle; lpImageFileName: LPWSTR; nSize: DWORD): DWORD; stdcall;
+
+{$EXTERNALSYM GetProcessImageFileName}
+function GetProcessImageFileName(hProcess: THandle; lpImageFileName: LPWSTR; nSize: DWORD): DWORD; stdcall;
+{$EXTERNALSYM GetProcessImageFileNameA}
+function GetProcessImageFileNameA(hProcess: THandle; lpImageFileName: LPSTR; nSize: DWORD): DWORD; stdcall;
+{$EXTERNALSYM GetProcessImageFileNameW}
+function GetProcessImageFileNameW(hProcess: THandle; lpImageFileName: LPWSTR; nSize: DWORD): DWORD; stdcall;
+
+{$EXTERNALSYM AttachConsole}
+function AttachConsole(dwProcessId: DWORD): BOOL; stdcall; external kernel32 name 'AttachConsole';
+
+function GetWindowModuleName(const aHandle: HWND): string;
+function GetPIDModuleName(const aProcessID: DWORD): string;
+
+function SetWindowProcessPriorityClass(const aWindow: HWND; const aPriority: cardinal): boolean;
+function GetWindowProcessPriorityClass(const aWindow: HWND): cardinal;
+
+function GetProcessIDs: TArray;
+
+implementation
+
+uses
+ EvilWorks.System.SysUtils;
+
+const
+ PsApi = 'PSAPI.dll';
+
+var
+ hPSAPI : THandle;
+ hKernel32 : THandle;
+ _GetProcessImageFileName : TGetProcessImageFileName;
+ _GetProcessImageFileNameA: TGetProcessImageFileNameA;
+ _GetProcessImageFileNameW: TGetProcessImageFileNameW;
+
+function CheckStubsLoaded: boolean;
+begin
+ if (hPSAPI = 0) then
+ begin
+ hPSAPI := LoadLibrary('PSAPI.dll');
+ if (hPSAPI < 32) then
+ begin
+ hPSAPI := 0;
+ Result := False;
+ Exit;
+ end;
+ // Kernel32.lib on Windows 7 and Windows Server 2008 R2;
+ // Psapi.lib if PSAPI_VERSION=1 on Windows 7 and Windows Server 2008 R2;
+ // Psapi.lib on Windows Server 2008, Windows Vista, Windows Server 2003, and Windows XP/2000
+ @_GetProcessImageFileName := GetProcAddress(hPSAPI, 'GetProcessImageFileNameW');
+ @_GetProcessImageFileNameA := GetProcAddress(hPSAPI, 'GetProcessImageFileNameA');
+ @_GetProcessImageFileNameW := GetProcAddress(hPSAPI, 'GetProcessImageFileNameW');
+ end;
+
+ if (Assigned(_GetProcessImageFileName) = False) then
+ begin
+ hKernel32 := LoadLibrary(kernel32);
+ if (hKernel32 < 32) then
+ begin
+ hKernel32 := 0;
+ Result := False;
+ Exit;
+ end;
+ @_GetProcessImageFileName := GetProcAddress(hKernel32, 'GetProcessImageFileNameW');
+ @_GetProcessImageFileNameA := GetProcAddress(hKernel32, 'GetProcessImageFileNameA');
+ @_GetProcessImageFileNameW := GetProcAddress(hKernel32, 'GetProcessImageFileNameW');
+ end;
+ Result := True;
+end;
+
+function GetProcessImageFileName(hProcess: THandle; lpImageFileName: LPWSTR; nSize: DWORD): DWORD;
+begin
+ if (CheckStubsLoaded) then
+ Result := _GetProcessImageFileName(hProcess, lpImageFileName, nSize)
+ else
+ Result := 0;
+end;
+
+function GetProcessImageFileNameA(hProcess: THandle; lpImageFileName: LPSTR; nSize: DWORD): DWORD;
+begin
+ if (CheckStubsLoaded) then
+ Result := _GetProcessImageFileNameA(hProcess, lpImageFileName, nSize)
+ else
+ Result := 0;
+end;
+
+function GetProcessImageFileNameW(hProcess: THandle; lpImageFileName: LPWSTR; nSize: DWORD): DWORD;
+begin
+ if (CheckStubsLoaded) then
+ Result := _GetProcessImageFileNameW(hProcess, lpImageFileName, nSize)
+ else
+ Result := 0;
+end;
+
+{ Gets filename of the executable to which a window belongs. }
+function GetWindowModuleName(const aHandle: HWND): string;
+var
+ processID : DWORD;
+ processHandle: THandle;
+ moduleArray : array of hModule;
+ arrayLen : DWORD;
+ len : DWORD;
+begin
+ Result := '';
+ processID := 1;
+ GetWindowThreadProcessId(aHandle, @processID);
+ processHandle := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, False, processID);
+ if (processHandle <= 0) then
+ RaiseLastOSError;
+ EnumProcessModules(processHandle, nil, 0, arrayLen);
+ SetLength(moduleArray, arrayLen div SizeOf(moduleArray[0]));
+ if (EnumProcessModules(processHandle, PDWord(@moduleArray[0]), arrayLen, arrayLen) = False) then
+ RaiseLastOSError;
+ SetLength(Result, MAX_PATH);
+ len := GetModuleFileNameEx(processHandle, moduleArray[0], PChar(Result), Length(Result));
+ if (len > 0) then
+ SetLength(Result, len);
+ CloseHandle(processHandle);
+end;
+
+{ Gets filename of the executable for a Process ID. }
+function GetPIDModuleName(const aProcessID: DWORD): string;
+var
+ processHandle: THandle;
+ ret : DWORD;
+ buffer : PChar;
+begin
+ Result := '';
+ if (aProcessID = 0) then
+ Exit('');
+ processHandle := OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION or PROCESS_VM_READ, False, aProcessID);
+ if (processHandle <= 0) then
+ begin
+ ret := GetLastError;
+ if (ret = ERROR_ACCESS_DENIED) then
+ Exit('System');
+ RaiseLastOSError;
+ end;
+ buffer := AllocMem(MAX_PATH);
+ ret := GetModuleFileNameEx(processHandle, 0, buffer, MAX_PATH);
+ CloseHandle(processHandle);
+ if (ret = 0) then
+ begin
+ FreeMem(buffer);
+ RaiseLastOSError;
+ end
+ else
+ begin
+ SetString(Result, buffer, ret);
+ FreeMem(buffer);
+ end;
+end;
+
+{ Sets priority of the process that owns the aWindow .}
+function SetWindowProcessPriorityClass(const aWindow: HWND; const aPriority: cardinal): boolean;
+var
+ processID : DWORD;
+ processHandle: THandle;
+begin
+ Result := False;
+
+ processID := 1;
+ GetWindowThreadProcessId(aWindow, @processID);
+
+ processHandle := OpenProcess(PROCESS_SET_INFORMATION, False, processID);
+ if (processHandle = 0) then
+ Exit;
+
+ Result := SetPriorityClass(processHandle, aPriority);
+end;
+
+{ Gets priority of the process that owns the aWindow. If failed returns 0. }
+function GetWindowProcessPriorityClass(const aWindow: HWND): cardinal;
+var
+ processID : DWORD;
+ processHandle: THandle;
+begin
+ Result := 0;
+
+ processID := 1;
+ GetWindowThreadProcessId(aWindow, @processID);
+
+ if (TOSVersion.Check(6)) then
+ processHandle := OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, False, processID)
+ else
+ processHandle := OpenProcess(PROCESS_QUERY_INFORMATION, False, processID);
+
+ if (processHandle = 0) then
+ Exit;
+
+ Result := GetPriorityClass(processHandle);
+end;
+
+{ Retrieves the process identifier for each process object in the system. }
+function GetProcessIDs: TArray;
+var
+ numReturned: DWORD;
+begin
+ SetLength(Result, 1024);
+
+ if (EnumProcesses(@Result[0], Length(Result) * SizeOf(DWORD), numReturned) = False) then
+ SetLength(Result, 0)
+ else if (numReturned > 0) then
+ SetLength(Result, numReturned div SizeOf(DWORD));
+end;
+
+end.
diff --git a/EvilWorks.System.RTTI.pas b/EvilWorks.System.RTTI.pas
new file mode 100644
index 0000000..09c4ad0
--- /dev/null
+++ b/EvilWorks.System.RTTI.pas
@@ -0,0 +1,310 @@
+unit EvilWorks.System.RTTI;
+
+interface
+
+uses
+ System.Classes,
+ System.SysUtils,
+ System.TypInfo,
+ System.IniFiles,
+ System.RTTI;
+
+type
+ EEvilRTTI = class(Exception);
+ EMethodNotFound = class(EEvilRTTI);
+
+function GetTypeKindName(const aTypeKind: TTypeKind): string;
+function InvokeObjectMethod(aClassInstance: TObject; const aMethod: string; const aParams: array of string): string;
+
+type
+ { Exceptions }
+ ERTTIIni = class(Exception);
+
+ { TRTTIIni }
+ TRTTIIni = class(TPersistent)
+ strict private
+ FFileName: string;
+ protected
+ { Override to set the name of the section where properties will be written. }
+ { If not overiden, ClassName will be used instead. }
+ function GetSectionName: string; virtual;
+
+ { Save and load to FileName. }
+ procedure Save;
+ procedure Load;
+ public
+ { Set the FileName to/from which to Save/Load. Do it before Load() or Save()... }
+ property FileName: string read FFileName write FFileName;
+ published
+ { Auto-Streamable properties go here. See Load() and Save() methods for supported data types. }
+ { If you nest TRTTIIni object properties, they get auto saved as well to FileName. You'll have }
+ { to declare them first (and their GetSectionName if you don't want auto-names). }
+ end;
+
+implementation
+
+uses
+ EvilWorks.System.StrUtils;
+
+resourcestring
+ SErrTypeNotFound = 'TRttiType %s not found.';
+ SErrTypeMethodNotFound = 'TRttiMethod %s not found.';
+
+function GetTypeKindName(const aTypeKind: TTypeKind): string;
+const
+ TTypeKindNames: array [0 .. 21] of string = (
+ 'tkUnknown', 'tkInteger', 'tkChar', 'tkEnumeration', 'tkFloat', 'tkString', 'tkSet', 'tkClass',
+ 'tkMethod', 'tkWChar', 'tkLString', 'tkWString', 'tkVariant', 'tkArray', 'tkRecord', 'tkInterface',
+ 'tkInt64', 'tkDynArray', 'tkUString', 'tkClassRef', 'tkPointer', 'tkProcedure'
+ );
+begin
+ Result := TTypeKindNames[Ord(aTypeKind)];
+end;
+
+function InvokeObjectMethod(aClassInstance: TObject; const aMethod: string; const aParams: array of string): string;
+var
+ rttiCtx : TRttiContext;
+ rttiType : TRttiType;
+ rttiMethod: TRttiMethod;
+
+ rttiParams: TArray;
+ rttiValues: TArray;
+ i : integer;
+ intVal : integer;
+begin
+ rttiCtx := TRttiContext.Create;
+ try
+ rttiType := rttiCtx.GetType(aClassInstance.ClassInfo);
+ if (rttiType = nil) then
+ raise EEvilRTTI.CreateFmt(SErrTypeNotFound, [aClassInstance.ClassName]);
+
+ rttiMethod := rttiType.GetMethod(aMethod);
+ if (rttiMethod = nil) then
+ raise EMethodNotFound.CreateFmt(SErrTypeMethodNotFound, [aMethod]);
+
+ rttiParams := rttiMethod.GetParameters;
+ if (Length(rttiParams) > 0) then
+ begin
+ if (Length(rttiParams) > Length(aParams)) then
+ raise Exception.Create(Format('RTTIInvokeTypeMethod: Parameter counts differ: Given %d, expected %d.', [Length(aParams), Length(rttiParams)]));
+
+ SetLength(rttiValues, Length(rttiParams));
+ for i := 0 to Length(rttiParams) - 1 do
+ begin
+ case rttiParams[i].ParamType.TypeKind of
+ tkUnknown:
+ begin
+ raise Exception.Create(Format('RTTIInvokeTypeMethod: Unknown parameter type for Method "%s" at index %d.', [aMethod, i]));
+ end;
+ tkChar, tkWChar, tkLString, tkUString, tkString:
+ begin
+ rttiValues[i] := aParams[i];
+ end;
+ tkWString:
+ begin
+ rttiValues[i] := TValue.From(widestring(aParams[i]));
+ end;
+ tkInteger:
+ begin
+ rttiValues[i] := StrToInt(aParams[i]);
+ end;
+ tkInt64:
+ begin
+ rttiValues[i] := StrToInt64(aParams[i]);
+ end;
+ tkFloat:
+ begin
+ rttiValues[i] := StrToFloat(aParams[i]);
+ end;
+ tkEnumeration:
+ begin
+ rttiValues[i] := TValue.FromOrdinal(rttiParams[i].ParamType.Handle, GetEnumValue(rttiParams[i].ParamType.Handle, aParams[i]));
+ end;
+ tkSet:
+ begin
+ intVal := StringToSet(rttiParams[i].ParamType.Handle, aParams[i]);
+ TValue.Make(@intVal, rttiParams[i].ParamType.Handle, rttiValues[i]);
+ end;
+ tkVariant:
+ begin
+ rttiValues[i] := TValue.FromVariant(variant(aParams[i]));
+ end;
+ tkMethod:
+ begin
+
+ end;
+ tkProcedure:
+ begin
+
+ end;
+ tkClass:
+ begin
+
+ end;
+ tkArray:
+ begin
+
+ end;
+ tkRecord:
+ begin
+
+ end;
+ tkInterface:
+ begin
+
+ end;
+ tkDynArray:
+ begin
+
+ end;
+ tkClassRef:
+ begin
+
+ end;
+ tkPointer:
+ begin
+
+ end;
+ end; { case }
+ end; { for }
+ end; { if }
+
+ Result := rttiMethod.Invoke(aClassInstance, rttiValues).ToString;
+ finally
+ rttiCtx.Free;
+ end;
+end;
+
+{ TRTTIIni }
+
+function TRTTIIni.GetSectionName: string;
+begin
+ Result := Self.ClassName;
+end;
+
+procedure TRTTIIni.Load;
+var
+ ini : TIniFile;
+ sub : TRTTIIni;
+ sl : TStringList;
+ i : integer;
+ v : integer;
+ def : string;
+ data : string;
+ rttiContext : TRttiContext;
+ rttiType : TRttiType;
+ rttiProperty : TRttiProperty;
+ rttiProperties: TArray;
+ rttiVal : TValue;
+begin
+ ini := TIniFile.Create(FileName);
+ sl := TStringList.Create;
+ rttiContext := TRttiContext.Create;
+ try
+ rttiType := rttiContext.GetType(Self.ClassInfo);
+ if (rttiType = nil) then
+ raise ERTTIIni.Create('TRTTIIni.Load(): Context.GetType() failed.');
+
+ ini.ReadSection(GetSectionName, sl);
+ for i := 0 to sl.Count - 1 do
+ begin
+ rttiProperty := rttiType.GetProperty(sl[i]);
+ if (rttiProperty <> nil) then
+ begin
+ if (rttiProperty.Visibility <> mvPublished) or (not rttiProperty.IsWritable) or (not rttiProperty.IsReadable) then
+ Continue;
+
+ def := rttiProperty.GetValue(Self).ToString;
+ data := ini.ReadString(GetSectionName, sl[i], def);
+
+ case rttiProperty.GetValue(Self).Kind of
+ tkWChar, tkLString, tkWString, tkString, tkChar, tkUString:
+ rttiVal := data;
+ tkInteger, tkInt64:
+ rttiVal := StrToInt(data);
+ tkFloat:
+ rttiVal := StrToFloat(data);
+ tkEnumeration:
+ rttiVal := TValue.FromOrdinal(rttiProperty.GetValue(Self).TypeInfo, GetEnumValue(rttiProperty.GetValue(Self).TypeInfo, data));
+ tkSet:
+ begin
+ v := StringToSet(rttiVal.TypeInfo, data);
+ TValue.Make(@v, rttiVal.TypeInfo, rttiVal);
+ end;
+ end;
+ rttiProperty.SetValue(Self, rttiVal);
+ end;
+ end;
+
+ rttiProperties := rttiType.GetProperties;
+ for rttiProperty in rttiProperties do
+ begin
+ if (rttiProperty.Visibility <> mvPublished) or (not rttiProperty.IsReadable) or (not rttiProperty.IsWritable) then
+ Continue;
+
+ if (rttiProperty.GetValue(Self).IsObject) then
+ begin
+ if (rttiProperty.GetValue(Self).AsObject is TRTTIIni) then
+ begin
+ sub := TRTTIIni(rttiProperty.GetValue(Self).AsObject);
+ sub.FileName := Self.FileName;
+ sub.Load;
+ end;
+ end;
+ end;
+
+ finally
+ rttiContext.Free;
+ sl.Free;
+ ini.Free;
+ end;
+end;
+
+procedure TRTTIIni.Save;
+var
+ ini : TIniFile;
+ sub : TRTTIIni;
+ rttiContext : TRttiContext;
+ rttiType : TRttiType;
+ rttiProperties: TArray;
+ rttiProperty : TRttiProperty;
+begin
+ if (FFileName = '') then
+ raise ERTTIIni.Create('TRTTIIni.Save(): FileName not specified.');
+
+ ini := TIniFile.Create(FileName);
+ rttiContext := TRttiContext.Create;
+ try
+ ForceDirectories(ExtractFileDir(FileName));
+ rttiType := rttiContext.GetType(Self.ClassInfo);
+ if (rttiType = nil) then
+ raise ERTTIIni.Create('TRTTIIni.Save(): Failed to get TRTTIType.');
+
+ rttiProperties := rttiType.GetProperties;
+ for rttiProperty in rttiProperties do
+ begin
+ if (rttiProperty.Visibility <> mvPublished) or (not rttiProperty.IsReadable) or (not rttiProperty.IsWritable) then
+ Continue;
+
+ if rttiProperty.GetValue(Self).Kind in [
+ tkWChar, tkLString, tkWString, tkString, tkChar, tkUString,
+ tkInteger, tkInt64, tkFloat, tkEnumeration, tkSet] then
+ ini.WriteString(GetSectionName, rttiProperty.Name, rttiProperty.GetValue(Self).ToString);
+
+ if (rttiProperty.GetValue(Self).IsObject) then
+ begin
+ if (rttiProperty.GetValue(Self).AsObject is TRTTIIni) then
+ begin
+ sub := TRTTIIni(rttiProperty.GetValue(Self).AsObject);
+ sub.FileName := Self.FileName;
+ sub.Save;
+ end;
+ end;
+ end;
+ finally
+ rttiContext.Free;
+ ini.Free;
+ end;
+end;
+
+end.
diff --git a/EvilWorks.System.StrUtils.inc b/EvilWorks.System.StrUtils.inc
new file mode 100644
index 0000000..b3a2647
--- /dev/null
+++ b/EvilWorks.System.StrUtils.inc
@@ -0,0 +1,63 @@
+const
+
+ CEmpty = '';
+ CTab = #9;
+ CLf = #10;
+ CCr = #13;
+ CCrLf = CCr + CLf;
+ CSpace = ' ';
+ C0 = '0';
+ C1 = '1';
+ C2 = '2';
+ C3 = '3';
+ C4 = '4';
+ C5 = '5';
+ C6 = '6';
+ C7 = '7';
+ C8 = '8';
+ C9 = '9';
+ CDot = '.';
+ CComma = ',';
+ CDoubleQuote = '"';
+ CSingleQuote = '''';
+ CColon = ':';
+ CSemiColon = ';';
+ CEquals = '=';
+ CMonkey = '@';
+ CPercent = '%';
+ CPlus = '+';
+ CMinus = '-';
+ CLBracket = '(';
+ CRBracket = ')';
+ CLSquareBracket = '[';
+ CRSquareBracket = ']';
+ CLCurlyBracket = '{';
+ CRCurlyBracket = '}';
+ CAsterisk = '*';
+ CExclam = '!';
+ CLessThan = '<';
+ CGreaterThan = '>';
+ CLadder = '#';
+ CFrontSlash = '/';
+ CBackSlash = '\';
+ CQuestionMark = '?';
+ CAmpersand = '&';
+ CDollar = '$';
+
+ CTrue = 'True';
+ CFalse = 'False';
+ CURIPrefixDelimiter = '://';
+ CURISchemeDelimiter = '://';
+ CComment = '//';
+
+ CNums = '0123456789';
+ CAlphaUpper = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
+ CAlphaLower = 'abcdefghijklmnopqrstuvwxyz';
+ CAlpha = CAlphaUpper + CAlphaLower;
+ CAlphaNums = CNums + CAlpha;
+ CVowelsLower = 'aeiou';
+ CVowelsUpper = 'AEIOU';
+ CVowels = CVowelsLower + CVowelsUpper;
+ CConsonantsLower = 'bcdfghjklmnpqrstvxyz';
+ CConsonantsUpper = 'BCDFGHJKLMNPQRSTVXYZ';
+ CConsonants = CConsonantsLower + CConsonantsUpper;
diff --git a/EvilWorks.System.StrUtils.pas b/EvilWorks.System.StrUtils.pas
new file mode 100644
index 0000000..7ea2b8e
--- /dev/null
+++ b/EvilWorks.System.StrUtils.pas
@@ -0,0 +1,1739 @@
+//
+// EvilLibrary by Vedran Vuk 2010-2012
+//
+// Name: EvilWorks.System.StrUtils
+// Description: A collection of pure pascal string parsing functions! :)
+// And still ~100x faster than Python, PHP, javascript... :P
+// File last change date: October 30th. 2012
+// File version: Dev 0.0.0
+// Licence: Free.
+//
+
+unit EvilWorks.System.StrUtils;
+
+interface
+
+uses
+ System.SysUtils,
+ System.StrUtils;
+
+{$I EvilWorks.System.StrUtils.inc}
+
+type
+ { Forward declarations }
+ TTokensEnumerator = class;
+
+ { TSplitOption }
+ { Options for TextSplit(), TextTokenize() }
+ TSplitOption = (
+ soNoDelSep, // Tokens will be added to list along with their trailing separators.
+ soCSSep, // Token separators are treated as Case Sensitive. SPEEDS UP! parsing.
+ soCSQot, // Quote character/string is treated as Case Sensitive. SPEEDS UP! parsing if [soQuoted].
+ soSingleSep, // Splitting will stop after the first separator; Two tokens total.
+ soQuoted, // Treat strings quoted/enclosed in Quote as single token.
+ soRemQuotes // Remove Quote from parsed out tokens.
+ );
+ TSplitOptions = set of TSplitOption;
+
+ { TPair }
+ { Your standard Key=Value pair record. }
+ TPair = record
+ Key: string;
+ Val: string;
+ end;
+
+ { TTokens }
+ { A helpful text array container for all sorts of formatting and parsing. }
+ { Can be declared as standalone (initialize with Clear), or returned by TextTokenize(). }
+ TTokens = record
+ private
+ FTokens: TArray;
+ FCount : Integer;
+ function GetToken(const aIndex: Integer): string;
+ procedure QuickSort(aStart, aEnd: Integer);
+ function GetPair(const aIndex: integer): TPair;
+ public
+ function GetEnumerator: TTokensEnumerator;
+
+ function FromToken(const aIndex: Integer; const aDelimiter: string = CSpace): string;
+ function ToToken(const aIndex: Integer; const aDelimiter: string = CSpace): string;
+ function AllTokens(const aDelimiter: string = CSpace): string;
+
+ procedure Add(const aText: string); overload;
+
+ procedure Add(const aKey, aVal: string); overload;
+ procedure Add(const aKey: string; const aVal: integer); overload;
+ procedure Add(const aKey: string; const aVal: boolean); overload;
+
+ procedure AddQ(const aKey, aVal: string); overload;
+ procedure AddQ(const aKey: string; const aVal: integer); overload;
+ procedure AddQ(const aKey: string; const aVal: boolean); overload;
+
+ procedure Exchange(aIndexA, aIndexB: Integer);
+ procedure Sort;
+ procedure Clear;
+
+ function ToArray(const aFromToken: integer = 0; const aToToken: integer = maxint): TArray; overload;
+
+ property Token[const aIndex: Integer]: string read GetToken; default;
+ property Pair[const aIndex: integer]: TPair read GetPair;
+ property Count: Integer read FCount;
+ function Empty: boolean;
+ end;
+
+ { TTokensEnumerator }
+ { Enumerator for TTokens. }
+ TTokensEnumerator = class
+ private
+ FIndex : integer;
+ FTokens: TTokens;
+ public
+ constructor Create(aTokens: TTokens);
+ function GetCurrent: string; inline;
+ function MoveNext: Boolean; inline;
+ property Current: string read GetCurrent;
+ end;
+
+{ Basic string handling }
+function TextPos(const aText, aSubText: string; const aCaseSens: boolean = False; const aOfs: Integer = 1): Integer;
+function TextCopy(const aText: string; const aStartIdx, aCount: Integer): string;
+function TextUpCase(const aText: string): string;
+function TextLoCase(const aText: string): string;
+function TextReplace(const aText, aSubText, aNewText: string; const aCaseSens: boolean = False): string;
+procedure TextAppend(var aText: string; const aAppendWith: string);
+
+{ More exotic functions of basic variety }
+procedure TextAppendWithFeed(var aText: string; const aAppendWith: string);
+procedure TextKeyValueAppend(var aOutStr: string; const aKey, aValue: string; const aAnd: boolean = True);
+function TextEscStr(const aText, aEscape: string): string;
+
+{ Comparison, extraction, splitting, tokenizing... }
+function TextLeft(const aText: string; const aCount: Integer): string;
+function TextRight(const aText: string; const aCount: Integer): string;
+function TextBegins(const aText, aBeginsWith: string; aCaseSens: boolean = False): boolean;
+function TextEnds(const aText, aEndsWith: string; aCaseSens: boolean = False): boolean;
+function TextSame(const aTextA, aTextB: string; const aCaseSens: boolean = False): boolean; inline;
+function TextEquals(const aTextA, aTextB: string; const aCaseSens: boolean = False): boolean;
+function TextInText(const aText, aContainsText: string; const aCaseSens: boolean = False): boolean;
+function TextInArray(const aText: string; const aArray: array of string; const aAnywhere: boolean = True; const aCaseSens: boolean = False): boolean;
+function TextWildcard(const aText, aWildCard: string): boolean;
+function TextEnclosed(const aText, aLeftSide, aRightSide: string; const aCaseSens: boolean = False): boolean; overload;
+function TextEnclosed(const aText, aEnclosedWith: string; const aCaseSens: boolean = False): boolean; overload;
+function TextEnclose(const aText, aEncloseWith: string): string;
+function TextUnEnclose(const aText, aEnclosedWith: string; const aCaseSens: boolean = False): string; overload;
+function TextUnEnclose(const aText, aLeftSide, aRightSide: string; const aCaseSens: boolean = False): string; overload;
+function TextFindEnclosed(const aText, aEnclLeft, aEnclRight: string; const aIdx: Integer; const aRemEncl: boolean = True; const aCaseSens: boolean = False): string; overload;
+function TextFindEnclosed(const aText, aEncl: string; const aIdx: Integer; const aRemEncl: boolean = True; const aCaseSens: boolean = False): string; overload;
+function TextQuote(const aText: string): string;
+function TextUnquote(const aText: string): string;
+function TextRemoveLineFeeds(const aText: string): string;
+function TextExtractLeft(var aText: string; const aSep: string; const aCaseSens: boolean = False; const aDelSep: boolean = True): string;
+function TextExtractRight(var aText: string; const aSep: string; const aCaseSens: boolean = False; const aDelSep: boolean = True): string;
+function TextFetchLeft(const aText, aSep: string; const aCaseSens: boolean = False; const aEmptyIfNoSep: boolean = True): string;
+function TextFetchRight(const aText, aSep: string; const aCaseSens: boolean = False; const aEmptyIfNoSep: boolean = True; const aSepFromRight: boolean = True): string;
+function TextFetchLine(const aText: string): string;
+function TextRemoveLeft(const aText, aRemove: string; const aCaseSens: boolean = False): string;
+function TextRemoveRight(const aText, aRemove: string; const aCaseSens: boolean = False): string;
+function TextSplit(const aText: string; const aSep: string = CSpace; const aQotStr: string = CDoubleQuote; const aOptions: TSplitOptions = [soCSSep, soCSQot]): TArray;
+function TextSplitMarkup(const aText: string; const aTrim: boolean = True): TArray;
+function TextTokenize(const aText: string; const aSep: string = CSpace; const aQotStr: string = CDoubleQuote; const aOptions: TSplitOptions = [soCSSep, soCSQot]): TTokens;
+function TextToken(const aText: string; const aIndex: integer; const aSeparator: string = CSpace): string;
+
+{ Conversion and formating rotines }
+function TextToInt(const aText: string; const aDefault: Integer): Integer;
+function TextFromBool(const aBoolean: boolean; const aUseBoolStrings: boolean = True): string;
+function TextFromInt(const aByte: byte): string; overload;
+function TextFromInt(const aInteger: integer): string; overload;
+function TextFromInt(const aCardinal: cardinal): string; overload;
+function TextFromInt(const aInt64: int64): string; overload;
+function TextFromFloat(const aFloat: double; const aDecimals: byte = 6): string; overload;
+function TextFromFloat(const aExtended: extended; const aDecimals: byte = 6): string; overload;
+function TextHexToDec(const aHexStr: string): cardinal;
+function TextIntToHex(const aValue, aDigits: integer): string;
+function TextMake(const aArgs: array of const; const aSeparator: string = ' '): string;
+
+{ URI text related functions }
+function TextURISplit(const aURI: string; var aPrefix, aHost, aPath: string): boolean; overload;
+function TextURISplit(const aURI: string; var aPrefix, aHost, aPath, aParams: string): boolean; overload;
+function TextURIGetPath(const aURI: string): string;
+function TextURIExtractParams(const aURI: string): string;
+function TextURIWithoutParams(const aURI: string): string;
+
+{ Various utility functions }
+function TextDump(const aData: pByte; const aSize: integer; const aBytesPerLine: byte = 16): string;
+procedure TextSave(const aText, aFileName: string);
+function TextOfChar(const aChar: char; const aLength: integer): string;
+
+{ IRC related functions }
+function SplitHostMask(const aHostMask: string; var aNickname, aIdent, aHost: string): boolean;
+
+{ Random string generation functions }
+function RandomNum: char;
+function RandomNums(const aLength: byte): string;
+function RandomAlphaLower: char;
+function RandomAlphaLowers(const aLength: byte): string;
+function RandomAlphaUpper: char;
+function RandomAlphaUppers(const aLength: byte): string;
+function RandomVowelLower: char;
+function RandomVowelUpper: char;
+function RandomVowel: char;
+function RandomConsonantLower: char;
+function RandomConsonantUpper: char;
+function RandomConsonant: char;
+function RandomString(const aLength: Integer; const aLowerCase, aUpperCase, aNumeric: boolean): string; overload;
+
+type
+ TTextHelper = record helper for string
+ public
+ function Len: integer;
+ function Size: integer; inline;
+ function Pos(const aSubText: string; const aCaseSens: boolean = False; const aOfs: Integer = 1): Integer;
+ function Copy(const aStartIdx, aCount: Integer): string;
+ function UpCase: string;
+ function LoCase: string;
+ function Replace(const aSubText, aNewText: string; const aCaseSens: boolean = False): string;
+ function Append(const aAppendWith: string; const aOnlyIfNotExists: boolean = False;
+ const aCaseSensitive: boolean = False): string;
+ function Left(const aLen: integer): string;
+ function Right(const aLen: integer): string;
+ function Begins(const aWith: string; const aCaseSensitive: boolean = False): boolean;
+ function Ends(const aWith: string; const aCaseSensitive: boolean = False): boolean;
+ function Equals(const aToText: string; const aCaseSensitive: boolean = False): boolean;
+ function ToInt(const aDefault: integer = -1): integer;
+ end;
+
+implementation
+
+{ TTextHelper }
+
+{ Length of Self in characters. }
+function TTextHelper.Len: integer;
+begin
+ Result := Length(Self);
+end;
+
+{ Size of Self in memory. Len * Self element size. }
+function TTextHelper.Size: integer;
+begin
+ Result := (Self.Len * StringElementSize(Self));
+end;
+
+{ Convert to int. Return aDefault on fail. }
+function TTextHelper.ToInt(const aDefault: integer): integer;
+var
+ code: Integer;
+begin
+ Val(Self, Result, code);
+ if (code <> 0) then
+ Result := aDefault;
+end;
+
+{ Get position of substring aSubText. 0 if not found. aOfs sets search start offset. }
+function TTextHelper.Pos(const aSubText: string; const aCaseSens: boolean; const aOfs: Integer): Integer;
+begin
+ Result := EvilWorks.System.StrUtils.TextPos(Self, aSubText, acaseSens, aOfs);
+end;
+
+{ Copy part of the string defined with aStartIdx and aCount. Returns nothing on invalid params or empty. }
+function TTextHelper.Copy(const aStartIdx, aCount: Integer): string;
+begin
+ Result := EvilWorks.System.StrUtils.TextCopy(Self, aStartIdx, aCount);
+end;
+
+{ Return UPPERCASE formatted self. }
+function TTextHelper.UpCase: string;
+begin
+ Result := EvilWorks.System.StrUtils.TextUpCase(Self);
+end;
+
+{ Return lowercase formatted self. }
+function TTextHelper.LoCase: string;
+begin
+ Result := EvilWorks.System.StrUtils.TextLoCase(Self);
+end;
+
+{ Replace aSubText in Self with aNewText, return result. aCaseSens sets case sensitivity of the search. }
+{ If aSubText is not found Self is just copied to result. }
+function TTextHelper.Replace(const aSubText, aNewText: string; const aCaseSens: boolean): string;
+begin
+ Result := EvilWorks.System.StrUtils.TextReplace(Self, aSubText, aNewText, aCaseSens);
+end;
+
+{ Append self with aAppendWith. If aOnlyIfExists will be appended only if Self is not already suffixed. }
+{ aCaseSensitive sets case sensitivity of existing aAppendWith suffix. }
+function TTextHelper.Append(const aAppendWith: string; const aOnlyIfNotExists: boolean;
+ const aCaseSensitive: boolean): string;
+begin
+ if (aOnlyIfNotExists) then
+ if (TextEquals(Self.Right(aAppendWith.Len), aAppendWith, aCaseSensitive)) then
+ Exit(Self);
+ Result := Self + aAppendWith;
+end;
+
+{ Return aLen chars from left of Self. If aLen > than Self.Len, just return all there is. }
+function TTextHelper.Left(const aLen: integer): string;
+begin
+ Result := TextCopy(Self, 1, aLen);
+end;
+
+{ Return aLen chars from right of Self. If aLen > than Self.Len, just return all there is. }
+function TTextHelper.Right(const aLen: integer): string;
+begin
+ Result := Self.Copy(Self.Len - aLen + 1, aLen);
+end;
+
+{ Checks if Self begins with aWith. aCaseSensitive sets search case sensitivity. }
+function TTextHelper.Begins(const aWith: string; const aCaseSensitive: boolean): boolean;
+begin
+ Result := TextEquals(Self.Left(aWith.Len), aWith, aCaseSensitive);
+end;
+
+{ Checks if Self ends with aWith. aCaseSensitive sets search case sensitivity. }
+function TTextHelper.Ends(const aWith: string; const aCaseSensitive: boolean): boolean;
+begin
+ Result := TextEquals(Self.Right(aWith.Len), aWith, aCaseSensitive);
+end;
+
+{ Checks if Self equals aToText. aCaseSensitive sets search case sensitivity. }
+function TTextHelper.Equals(const aToText: string; const aCaseSensitive: boolean): boolean;
+begin
+ if (aCaseSensitive) then
+ Result := (Self = aToText)
+ else
+ Result := SameText(Self, aToText);
+end;
+
+{ Combines Pos and PosEx. }
+function TextPos(const aText, aSubText: string; const aCaseSens: boolean = False; const aOfs: Integer = 1): Integer;
+begin
+ if (aCaseSens = False) then
+ Result := PosEx(LowerCase(aSubText), LowerCase(aText), aOfs)
+ else
+ Result := PosEx(aSubText, aText, aOfs);
+end;
+
+{ Safe Copy. Won't go apeshit if aStartIdx is > Length(aText), instead it just returns empty string. }
+function TextCopy(const aText: string; const aStartIdx, aCount: Integer): string;
+begin
+ { Safe Copy. Won't go apeshit if aStartIdx is > Length(aText). }
+ if (aStartIdx > Length(aText)) then
+ Exit(CEmpty);
+ Result := Copy(aText, aStartIdx, aCount);
+end;
+
+{ Uppercase }
+function TextUpCase(const aText: string): string;
+var
+ i: integer;
+begin
+ SetLength(Result, Length(aText));
+ for i := 0 to Length(aText) - 1 do
+ Result[1] := UpCase(aText[i]);
+end;
+
+{ Lowercase }
+function TextLoCase(const aText: string): string;
+begin
+ Result := LowerCase(aText);
+end;
+
+{ Replaces all occurances of aSubText with aNewText in aText. }
+function TextReplace(const aText, aSubText, aNewText: string; const aCaseSens: boolean = False): string;
+var
+ i: Integer;
+ j: Integer;
+begin
+ Result := CEmpty;
+
+ if (aText = CEmpty) then
+ Exit;
+
+ j := 1;
+ while (True) do
+ begin
+ i := TextPos(aText, aSubText, aCaseSens, j);
+ if (i > 0) then
+ begin
+ Result := Result + TextCopy(aText, j, i - j) + aNewText;
+ i := i + Length(aSubText);
+ j := i;
+ end
+ else
+ begin
+ Result := Result + TextRight(aText, Length(aText) - j + 1);
+ Exit;
+ end;
+ end;
+end;
+
+{ Append aText with aAppendWith }
+procedure TextAppend(var aText: string; const aAppendWith: string);
+begin
+ aText := aText + aAppendWith;
+end;
+
+{ Append aText with aAppendWith and CRLF. }
+procedure TextAppendWithFeed(var aText: string; const aAppendWith: string);
+begin
+ aText := aText + aAppendWith + CCrLf;
+end;
+
+{ Append aKey="aValue" pair to aOutStr and add ', ' if aAnd: aKey="aValue", }
+procedure TextKeyValueAppend(var aOutStr: string; const aKey, aValue: string; const aAnd: boolean = True);
+begin
+ if (aAnd) then
+ aOutStr := aOutStr + aKey + '="' + aValue + '", '
+ else
+ aOutStr := aOutStr + aKey + '="' + aValue + '"';
+end;
+
+{ Escape/replace all %s tokens in aText with aEscape}
+function TextEscStr(const aText, aEscape: string): string;
+begin
+ Result := TextReplace(aText, '%s', aEscape, False);
+end;
+
+{ Copies aCount chars from Left of aText. }
+function TextLeft(const aText: string; const aCount: Integer): string;
+begin
+ Result := TextCopy(aText, 1, aCount);
+end;
+
+{ Copies aCount chars from Right of aText. }
+function TextRight(const aText: string; const aCount: Integer): string;
+begin
+ Result := TextCopy(aText, Length(aText) - aCount + 1, aCount);
+end;
+
+{ Checks if aText begins with aBeginsWith. }
+function TextBegins(const aText, aBeginsWith: string; aCaseSens: boolean = False): boolean;
+begin
+ if (aCaseSens) then
+ Result := (TextLeft(aText, Length(aBeginsWith)) = aBeginsWith)
+ else
+ Result := (SameText(TextLeft(aText, Length(aBeginsWith)), aBeginsWith));
+end;
+
+{ Checks if aText ends with aEndsWith. }
+function TextEnds(const aText, aEndsWith: string; aCaseSens: boolean = False): boolean;
+begin
+ if (aCaseSens) then
+ Result := (TextRight(aText, Length(aEndsWith)) = aEndsWith)
+ else
+ Result := (SameText(TextRight(aText, Length(aEndsWith)), aEndsWith));
+end;
+
+{ Checks if aTextA is same as aTextB. Alias for TextEquals. }
+function TextSame(const aTextA, aTextB: string; const aCaseSens: boolean): boolean; inline;
+begin
+ Result := TextEquals(aTextA, aTextB, aCaseSens);
+end;
+
+{ Checks if aTextA is same as aTextB. }
+function TextEquals(const aTextA, aTextB: string; const aCaseSens: boolean): boolean;
+begin
+ if (aCaseSens) then
+ Result := (aTextA = aTextB)
+ else
+ Result := SameText(aTextA, aTextB);
+end;
+
+{ Checks if aText contains aContainsText. }
+function TextInText(const aText, aContainsText: string; const aCaseSens: boolean): boolean;
+begin
+ Result := (TextPos(aText, aContainsText, aCaseSens) <> 0);
+end;
+
+{ Checks if aText matches any entries in aArray. If aAnywhere, aText matches anywhere in an aArray item. }
+function TextInArray(const aText: string; const aArray: array of string; const aAnywhere: boolean; const aCaseSens: boolean): boolean;
+var
+ i: integer;
+begin
+ Result := False;
+ for i := 0 to high(aArray) do
+ begin
+ if (aAnywhere) then
+ begin
+ if (TextInText(aArray[i], aText, aCaseSens)) then
+ Exit(True);
+ end
+ else
+ begin
+ if (TextEquals(aArray[i], aText, aCaseSens)) then
+ Exit(True);
+ end;
+ end;
+end;
+
+{ Matches aText agains aWildCard. Case insensitive. * and ? supported. For IRC. }
+function TextWildcard(const aText, aWildCard: string): boolean;
+var
+ ps: pchar;
+ pw: pchar;
+ mp: pchar;
+ cp: pchar;
+begin
+ if (aText = '') or (aWildCard = '') then
+ Exit(False);
+
+ ps := @aText[1];
+ pw := @aWildCard[1];
+ mp := nil;
+ cp := nil;
+
+ while ((ps^ <> #0) and (pw^ <> CAsterisk)) do
+ begin
+ if ((pw^ <> CQuestionMark) and (SameText(ps^, pw^) = False)) then
+ Exit(False);
+ Inc(ps);
+ Inc(pw);
+ end;
+
+ while (ps^ <> #0) do
+ begin
+ if (pw^ = CAsterisk) then
+ begin
+ Inc(pw);
+ if (pw^ = #0) then
+ Exit(True);
+ mp := pw;
+ cp := @ps[1];
+ end
+ else
+ begin
+ if (SameText(ps^, pw^)) or (pw^ = CQuestionMark) then
+ begin
+ Inc(ps);
+ Inc(pw);
+ end
+ else
+ begin
+ ps := cp;
+ Inc(cp);
+ pw := mp;
+ end;
+ end;
+ end;
+
+ while (pw^ = CAsterisk) do
+ Inc(pw);
+
+ Result := (pw^ = #0);
+end;
+
+{ Checks if left of aText is prefixed with aLeftSide and right of aText is suffixed with aRightSide. }
+function TextEnclosed(const aText, aLeftSide, aRightSide: string; const aCaseSens: boolean = False): boolean;
+begin
+ if (aCaseSens) then
+ Result := ((TextLeft(aText, Length(aLeftSide)) = aLeftSide) and (TextRight(aText, Length(aRightSide)) = aRightSide))
+ else
+ Result := (SameText(TextLeft(aText, Length(aLeftSide)), aLeftSide) and SameText(TextRight(aText, Length(aRightSide)), aRightSide));
+end;
+
+{ Checks if aText is prefixed and suffixed with aEnclosedWith. e.g. xXxTeenageDawgxXx }
+function TextEnclosed(const aText, aEnclosedWith: string; const aCaseSens: boolean = False): boolean;
+begin
+ Result := TextEnclosed(aText, aEnclosedWith, aEnclosedWith, aCaseSens);
+end;
+
+{ Encloses a aText within aEncloseWith. }
+function TextEnclose(const aText, aEncloseWith: string): string;
+begin
+ Result := aEncloseWith + aText + aEncloseWith;
+end;
+
+{ Removes aEnclosedWith prefix AND/OR suffix from aText. }
+function TextUnEnclose(const aText, aEnclosedWith: string; const aCaseSens: boolean = False): string;
+begin
+ Result := TextUnEnclose(aText, aEnclosedWith, aEnclosedWith, aCaseSens);
+end;
+
+{ Removes aLeftSide prefix from Left AND/OR aRightSide suffix from Right side of aText. }
+function TextUnEnclose(const aText, aLeftSide, aRightSide: string; const aCaseSens: boolean = False): string; overload;
+begin
+ if (aCaseSens) then
+ begin
+ if (TextLeft(aText, Length(aLeftSide)) = aLeftSide) then
+ Result := TextCopy(aText, Length(aLeftSide) + 1, MaxInt)
+ else
+ Result := aText;
+
+ if (TextRight(Result, Length(aRightSide)) = aRightSide) then
+ Delete(Result, Length(Result), Length(aRightSide));
+ end
+ else
+ begin
+ if (SameText(TextLeft(aText, Length(aLeftSide)), aLeftSide)) then
+ Result := TextCopy(aText, Length(aLeftSide) + 1, MaxInt)
+ else
+ Result := aText;
+
+ if (SameText(TextRight(Result, Length(aRightSide)), aRightSide)) then
+ Delete(Result, Length(Result), Length(aRightSide));
+ end;
+end;
+
+{ Find and return aIdx(th) (0-based) occurance of text in aText that is enlosed with aEnclLeft on left and }
+{ aEnclRight on the right of text. If aRemEncl, aEnclLeft and aEnclRight are removed from result, aCaseSens }
+{ makes the search Case-sensitive. If no enclosed text is found, result is an empty string. }
+function TextFindEnclosed(const aText, aEnclLeft, aEnclRight: string; const aIdx: Integer; const aRemEncl: boolean = True; const aCaseSens: boolean = False): string;
+var
+ a : Integer;
+ b : Integer;
+ ea: integer;
+ eb: integer;
+ l : Integer;
+ i : Integer;
+begin
+ Result := CEmpty;
+
+ if (aText = CEmpty) then
+ Exit;
+
+ a := 1;
+ b := 1;
+ l := Length(aText);
+ ea := Length(aEnclLeft);
+ eb := Length(aEnclRight);
+ i := 0;
+ while (i <= aIdx) and (a < l) and (b < l) do
+ begin
+ a := TextPos(aText, aEnclLeft, aCaseSens, b);
+ if (a = 0) then
+ Exit;
+
+ b := TextPos(aText, aEnclRight, aCaseSens, a + ea);
+ if (b <= a) then
+ Exit;
+
+ if (i = aIdx) then
+ begin
+ if (aRemEncl) then
+ Result := TextCopy(aText, a + ea, b - a - ea)
+ else
+ Result := TextCopy(aText, a, b - a + eb);
+ end;
+ a := b + eb;
+ b := a;
+ Inc(i);
+ end; { while }
+end;
+
+{ Find and return aIdx occurance of text in aText that is enlosed with aEncl. If aRemEncl, aEncl is removed }
+{ from result. aCase sens makes the search Case-sensitive. If no enclosed text is found, result is empty. }
+function TextFindEnclosed(const aText, aEncl: string; const aIdx: Integer; const aRemEncl: boolean; const aCaseSens: boolean): string;
+begin
+ Result := TextFindEnclosed(aText, aEncl, aEncl, aIdx, aRemEncl, aCaseSens);
+end;
+
+{ Encloses aText with Double quotes. "Got it?" }
+function TextQuote(const aText: string): string;
+begin
+ Result := TextEnclose(aText, CDoubleQuote);
+end;
+
+{ Removes Double quote prefix AND/OR suffix from aText. }
+function TextUnquote(const aText: string): string;
+begin
+ Result := TextUnEnclose(aText, CDoubleQuote);
+end;
+
+{ Strips $0D and $0A from end of text until it finds no more. }
+function TextRemoveLineFeeds(const aText: string): string;
+var
+ i: Integer;
+begin
+ i := Length(aText);
+ while (i > 0) and ((aText[i] = CCr) or (aText[i] = CLf)) do
+ Dec(i);
+ Result := TextCopy(aText, 1, i);
+end;
+
+{ Removes string from Left of aText to aSep. If aSep is not found, nothing is returned or removed. }
+{ aSep search begins from Left of aText. If aDelSep is false returns aSep as well. }
+function TextExtractLeft(var aText: string; const aSep: string; const aCaseSens: boolean = False; const aDelSep: boolean = True): string;
+var
+ i: Integer;
+begin
+ i := TextPos(aText, aSep, aCaseSens);
+ if (i > 0) then
+ begin
+ Result := TextCopy(aText, 1, i - 1);
+ Delete(aText, 1, i - 1);
+ if (aDelSep) then
+ Delete(aText, 1, Length(aSep));
+ end;
+end;
+
+{ Removes string from Right of aText to aSep. If aSep is not found, nothing is returned or removed. }
+{ aSep search begins from Right of aText. If aDelSep is false returns aSep as well. }
+function TextExtractRight(var aText: string; const aSep: string; const aCaseSens: boolean = False; const aDelSep: boolean = True): string;
+var
+ i, ofs: Integer;
+begin
+ i := 0;
+ ofs := 1;
+ while (ofs <> 0) do
+ begin
+ ofs := TextPos(aText, aSep, aCaseSens, ofs);
+ if (ofs <> 0) then
+ begin
+ i := ofs;
+ Inc(ofs);
+ end
+ else
+ Break;
+ end;
+
+ if (i <> 0) then
+ begin
+ Result := TextRight(aText, Length(aText) - i);
+ Delete(aText, i, MaxInt);
+ end;
+end;
+
+{ Copies string from Left of aText to aSep. If aSep is not found, returns nothing. }
+{ aSep search begins from Left of aText. }
+function TextFetchLeft(const aText, aSep: string; const aCaseSens: boolean = False; const aEmptyIfNoSep: boolean = True): string;
+var
+ i: Integer;
+begin
+ i := TextPos(aText, aSep, aCaseSens);
+ if (i > 0) then
+ Result := TextLeft(aText, i - 1)
+ else if (aEmptyIfNoSep) then
+ Result := CEmpty
+ else
+ Result := aText;
+end;
+
+{ Copies string from Right of aText to aSep. If aSep is not found returns nothing. }
+{ If aSepFromRight aSep search begins from Right of aText, else from left. }
+function TextFetchRight(const aText, aSep: string; const aCaseSens: boolean; const aEmptyIfNoSep: boolean; const aSepFromRight: boolean): string;
+var
+ i, ofs: Integer;
+begin
+ if (aSepFromRight) then
+ begin
+ i := 0;
+ ofs := 1;
+ while (ofs <> 0) do
+ begin
+ ofs := TextPos(aText, aSep, aCaseSens, ofs);
+ if (ofs <> 0) then
+ begin
+ i := ofs;
+ Inc(ofs);
+ end
+ else
+ Break;
+ end;
+
+ if (i = 0) then
+ if (aEmptyIfNoSep) then
+ Exit(CEmpty)
+ else
+ Exit(aText);
+ Result := TextRight(aText, Length(aText) - i - Length(aSep) + 1);
+ end
+ else
+ begin
+ i := TextPos(aText, aSep, aCaseSens);
+ if (i > 0) then
+ Result := TextRight(aText, Length(aText) - i - Length(aSep) + 1)
+ else if (aEmptyIfNoSep) then
+ Result := CEmpty
+ else
+ Result := aText;
+ end;
+end;
+
+{ Copies string from Left of aText to first CRLF separator. If aSep is not found, returns nothing. }
+function TextFetchLine(const aText: string): string;
+begin
+ Result := TextFetchLeft(atext, #13#10, True);
+end;
+
+{ Removes aRemove from the Left of aText, returns the rest. }
+function TextRemoveLeft(const aText, aRemove: string; const aCaseSens: boolean = False): string;
+begin
+ if (TextBegins(aText, aRemove, aCaseSens)) then
+ Result := TextCopy(aText, Length(aRemove) + 1, MaxInt)
+ else
+ Result := aText;
+end;
+
+{ Removes aRemove from the Right of aText, returns the rest. }
+function TextRemoveRight(const aText, aRemove: string; const aCaseSens: boolean = False): string;
+begin
+ if (TextEnds(aText, aRemove, aCaseSens)) then
+ Result := TextCopy(aText, 1, Length(aText) - Length(aRemove))
+ else
+ Result := aText;
+end;
+
+{ Splits aText on aSep(s), returns an array of strings. }
+function TextSplit(const aText: string; const aSep: string; const aQotStr: string; const aOptions: TSplitOptions): TArray;
+var
+ Count: Integer;
+
+ procedure Add(const aString: string);
+ begin
+ if (aString = CEmpty) then
+ Exit;
+ Inc(Count);
+ SetLength(Result, Count);
+ Result[Count - 1] := aString;
+ end;
+
+var
+ strLen: Integer;
+ sepLen: Integer;
+ qotLen: Integer;
+ cpyPos: Integer;
+ ofsPos: Integer;
+ tokPos: Integer;
+ qotPos: Integer;
+
+begin
+ if ((aText = CEmpty) or (aSep = CEmpty)) then
+ Exit;
+
+ if (soQuoted in aOptions) then
+ if (aQotStr = CEmpty) then
+ Exit;
+
+ Count := 0;
+
+ strLen := Length(aText);
+ sepLen := Length(aSep);
+
+ cpyPos := 1;
+ ofsPos := 1;
+
+ if (soQuoted in aOptions) then
+ begin
+ qotLen := Length(aQotStr);
+ qotPos := 1;
+ while (True) do
+ begin
+ tokPos := TextPos(aText, aSep, (soCSSep in aOptions), ofsPos);
+ qotPos := TextPos(aText, aQotStr, (soCSQot in aOptions), qotPos);
+ if (qotPos < tokPos) and (qotPos <> 0) then
+ begin
+ qotPos := TextPos(aText, aQotStr, (soCSQot in aOptions), qotPos + qotLen);
+ if (qotPos <> 0) then
+ begin
+ ofsPos := qotPos;
+ qotPos := qotPos + qotLen;
+ end
+ else
+ qotPos := MaxInt;
+ end
+ else
+ begin
+ if (tokPos = 0) then
+ begin
+ Add(TextCopy(aText, cpyPos, MaxInt));
+ Exit;
+ end
+ else
+ begin
+ if (soNoDelSep in aOptions) then
+ begin
+ if (soRemQuotes in aOptions) then
+ Add(TextUnEnclose(TextCopy(aText, cpyPos, tokPos - cpyPos + sepLen), aQotStr, (soCSQot in aOptions)))
+ else
+ Add(TextCopy(aText, cpyPos, tokPos - cpyPos + sepLen))
+ end
+ else
+ begin
+ if (soRemQuotes in aOptions) then
+ Add(TextUnEnclose(TextCopy(aText, cpyPos, tokPos - cpyPos), aQotStr, (soCSQot in aOptions)))
+ else
+ Add(TextCopy(aText, cpyPos, tokPos - cpyPos));
+ end;
+ ofsPos := tokPos + sepLen;
+ qotPos := ofsPos;
+ cpyPos := ofsPos;
+ end;
+ end;
+ end;
+ end
+ else
+ begin
+ while (True) do
+ begin
+ tokPos := TextPos(aText, aSep, (soCSSep in aOptions), ofsPos);
+ if (tokPos > 0) then
+ begin
+ if (soNoDelSep in aOptions) then
+ Add(TextCopy(aText, ofsPos, tokPos - ofsPos + sepLen))
+ else
+ Add(TextCopy(aText, ofsPos, tokPos - ofsPos));
+ ofsPos := tokPos + sepLen;
+ if (soSingleSep in aOptions) then
+ begin
+ Add(TextCopy(aText, ofsPos, MaxInt));
+ Exit;
+ end;
+ end
+ else
+ begin
+ Add(TextRight(aText, strLen - ofsPos + 1));
+ Exit;
+ end;
+ end;
+ end;
+end;
+
+{ Splits the line with HTML/XML markup into a list of tokens. No pair matching performed. Example: }
+{ text1text2 to , text1, , , text2 and . }
+function TextSplitMarkup(const aText: string; const aTrim: boolean): TArray;
+var
+ Count: Integer;
+
+ procedure Add(const aString: string);
+ begin
+ if (aString = CEmpty) then
+ Exit;
+ Inc(Count);
+ SetLength(Result, Count);
+ if (aTrim) then
+ Result[Count - 1] := Trim(aString)
+ else
+ Result[Count - 1] := aString;
+ end;
+
+var
+ strLen: Integer;
+ cpyPos: Integer;
+ ofsPos: Integer;
+begin
+ strLen := Length(aText);
+ if (strLen = 0) then
+ Exit;
+
+ Count := 0;
+ ofsPos := 1;
+ cpyPos := 1;
+
+ while (cpyPos <= strLen) do
+ begin
+ if (aText[cpyPos] = CLessThan) then
+ begin
+ if (ofsPos <> cpyPos) then
+ begin
+ Add(TextCopy(aText, ofsPos, cpyPos - ofsPos));
+ ofsPos := cpyPos;
+ end
+ else
+ Inc(cpyPos);
+ end
+ else if (aText[cpyPos] = CGreaterThan) then
+ begin
+ if (ofsPos <> cpyPos) then
+ begin
+ Add(TextCopy(aText, ofsPos, cpyPos - ofsPos + 1));
+ Inc(cpyPos);
+ ofsPos := cpyPos;
+ end
+ else
+ Inc(cpyPos);
+ end
+ else
+ Inc(cpyPos);
+ end;
+
+ if (ofsPos < cpyPos) then
+ Add(TextCopy(aText, ofsPos, MaxInt));
+end;
+
+{ Splits aText on aSep(s), returns TTokens record. }
+function TextTokenize(const aText: string; const aSep: string; const aQotStr: string; const aOptions: TSplitOptions): TTokens;
+begin
+ Result.FTokens := TextSplit(aText, aSep, aQotStr, aOptions);
+ Result.FCount := Length(Result.FTokens);
+end;
+
+{ Returns token at aIndex from aText split by aSeparator. }
+function TextToken(const aText: string; const aIndex: integer; const aSeparator: string = CSpace): string;
+var
+ tokens: TTokens;
+begin
+ tokens := TextTokenize(aText);
+ Result := tokens[aIndex];
+end;
+
+{ Converts a string to an integer. }
+function TextToInt(const aText: string; const aDefault: Integer): Integer;
+var
+ code: Integer;
+begin
+ Val(aText, Result, code);
+ if (code <> 0) then
+ Result := aDefault;
+end;
+
+{ Converts a byte to a string. }
+function TextFromInt(const aByte: byte): string;
+begin
+{$WARNINGS OFF}
+ Str(aByte, Result);
+{$WARNINGS ON}
+end;
+
+{ Converts an integer to a string. }
+function TextFromInt(const aInteger: integer): string;
+begin
+{$WARNINGS OFF}
+ Str(aInteger, Result);
+{$WARNINGS ON}
+end;
+
+{ Converts a cardinal to a string. }
+function TextFromInt(const aCardinal: cardinal): string;
+begin
+{$WARNINGS OFF}
+ Str(aCardinal, Result);
+{$WARNINGS ON}
+end;
+
+{ Converts an int64 to a string. }
+function TextFromInt(const aInt64: int64): string;
+begin
+{$WARNINGS OFF}
+ Str(aInt64, Result);
+{$WARNINGS ON}
+end;
+
+{ Converts a boolean to string. }
+function TextFromBool(const aBoolean: boolean; const aUseBoolStrings: boolean): string;
+begin
+ if (aBoolean) then
+ if (aUseBoolStrings) then
+ Exit('True')
+ else
+ Exit('1');
+
+ if (aBoolean = False) then
+ if (aUseBoolStrings) then
+ Exit('False')
+ else
+ Exit('0');
+end;
+
+{ Converts a float to string. }
+function TextFromFloat(const aFloat: double; const aDecimals: byte): string;
+begin
+{$WARNINGS OFF}
+ Str(aFloat: 1: aDecimals, Result);
+{$WARNINGS ON}
+end;
+
+{ Converts an extended to string. }
+function TextFromFloat(const aExtended: extended; const aDecimals: byte = 6): string;
+begin
+{$WARNINGS OFF}
+ Str(aExtended: 1: aDecimals, Result);
+{$WARNINGS ON}
+end;
+
+{ Converts a hex string to an integer. Input example: "DEADBEEF". }
+function TextHexToDec(const aHexStr: string): cardinal;
+var
+ c: cardinal;
+ b: byte;
+begin
+ Result := 0;
+ if (Length(aHexStr) <> 0) then
+ begin
+ c := 1;
+ b := Length(aHexStr) + 1;
+ repeat
+ Dec(b);
+ if (aHexStr[b] <= '9') then
+ Result := (Result + (cardinal(aHexStr[b]) - 48) * c)
+ else
+ Result := (Result + (cardinal(aHexStr[b]) - 55) * c);
+
+ c := c * 16;
+ until (b = 1);
+ end;
+end;
+
+{ Converts aValue to Hex string with aDigits minimum width. }
+function TextIntToHex(const aValue, aDigits: integer): string;
+begin
+ Result := IntToHex(aValue, aDigits);
+end;
+
+{ Converts and appends all parameters together. Parameters can be of mixed types, but not constants. }
+function TextMake(const aArgs: array of const; const aSeparator: string): string;
+var
+ i: integer;
+begin
+ Result := '';
+ for i := 0 to high(aArgs) do
+ begin
+ case aArgs[i].VType of
+ vtInteger:
+ Result := Result + TextFromInt(aArgs[i].VInteger);
+ vtBoolean:
+ Result := Result + TextFromBool(aArgs[i].VBoolean);
+ vtChar:
+ Result := Result + string(aArgs[i].VChar);
+ vtExtended:
+ Result := Result + TextFromFloat(aArgs[i].VExtended^);
+ vtString:
+ Result := Result + string(aArgs[i].VString^);
+ vtPChar:
+ Result := Result + string(aArgs[i].VPChar);
+ vtObject:
+ Result := Result + aArgs[i].VObject.ClassName;
+ vtClass:
+ Result := Result + aArgs[i].VClass.ClassName;
+ vtAnsiString:
+ Result := Result + string(aArgs[i].VAnsiString);
+ vtUnicodeString:
+ Result := Result + string(aArgs[i].VUnicodeString);
+ vtCurrency:
+ Result := Result + TextFromFloat(aArgs[i].VCurrency^);
+ vtVariant:
+ Result := Result + string(aArgs[i].VVariant^);
+ vtInt64:
+ Result := Result + TextFromInt(aArgs[i].VInt64^);
+ end;
+
+ if (i <> high(aArgs)) then
+ Result := Result + aSeparator;
+ end;
+end;
+
+{ Splits an URI into parts: http://goatse.cx/images/goatse.jpg = http, goatse.cx, images/goatse.jpg }
+function TextURISplit(const aURI: string; var aPrefix, aHost, aPath: string): boolean;
+var
+ rPrefix, rHost, rPath, rParams: string;
+begin
+ Result := TextURISplit(aURI, rPrefix, rHost, rPath, rParams);
+end;
+
+{ Splits an URI into parts: http://goatse.cx/images/goatse.jpg = http, goatse.cx, images/goatse.jpg, par=val&par2=val2 }
+function TextURISplit(const aURI: string; var aPrefix, aHost, aPath, aParams: string): boolean; overload;
+var
+ offs: Integer;
+ i : Integer;
+begin
+ Result := False;
+
+ if (aURI = CEmpty) then
+ Exit;
+
+ offs := 0;
+
+ // Extract prefix.
+ i := TextPos(aURI, CURIPrefixDelimiter);
+ if (i > 0) then
+ begin
+ aPrefix := TextLeft(aURI, i - 1);
+ offs := i + Length(CURIPrefixDelimiter);
+ end;
+
+ // Extract host.
+ if (offs = 0) then
+ begin
+ i := TextPos(aURI, CFrontSlash);
+ if (i > 0) then
+ begin
+ aHost := TextCopy(aURI, offs, i - 1);
+ offs := i;
+ end;
+ end
+ else
+ begin
+ i := TextPos(aURI, CFrontSlash, True, offs);
+ if (i > 0) then
+ begin
+ aHost := TextCopy(aURI, offs, i - offs);
+ offs := i;
+ end;
+ end;
+
+ // Extract path.
+ if (offs = 0) then
+ begin
+ i := TextPos(aURI, CQuestionMark);
+ if (i > 0) then
+ begin
+ aPath := TextCopy(aURI, offs, i - 1);
+ // The rest are params
+ aParams := TextCopy(aURI, i + 1, MaxInt);
+ end
+ else
+ begin
+ aPath := TextCopy(aURI, offs, MaxInt);
+ Exit(True);
+ end;
+ end
+ else
+ begin
+ i := TextPos(aURI, CQuestionMark, True, offs);
+ if (i > 0) then
+ begin
+ aPath := TextCopy(aURI, offs, i - offs);
+ // The rest are params
+ aParams := TextCopy(aURI, i + 1, MaxInt);
+ end
+ else
+ begin
+ aPath := TextCopy(aURI, offs, MaxInt);
+ Exit(True);
+ end;
+ end;
+
+ Result := True;
+end;
+
+{ Extracts Path from an URL }
+function TextURIGetPath(const aURI: string): string;
+var
+ prefix, domain, path: string;
+begin
+ if (TextURISplit(aURI, prefix, domain, path)) then
+ Result := path
+ else
+ Result := CEmpty;
+end;
+
+{ Url encodes(percent encodes) a string. }
+function TextURIEncode(const aText: string): string;
+var
+ i : Integer;
+ Ch: char;
+begin
+ Result := '';
+ for i := 1 to Length(aText) do
+ begin
+ Ch := aText[i];
+ if ((Ch >= '0') and (Ch <= '9')) or ((Ch >= 'a') and (Ch <= 'z')) or
+ ((Ch >= 'A') and (Ch <= 'Z')) or (Ch = '.') or (Ch = '-') or (Ch = '_')
+ or (Ch = '~') then
+ Result := Result + Ch
+ else
+ begin
+ Result := Result + '%' + IntToHex(Ord(Ch), 2);
+ end;
+ end;
+end;
+
+{ Url decodes(percent decodes) a string. }
+function TextURIDecode(const aText: string): string;
+var
+ i: Integer;
+ l: Integer;
+begin
+ Result := CEmpty;
+
+ i := 1;
+ l := Length(aText);
+ while (i <= l) do
+ begin
+ if (aText[i] = CPercent) then
+ begin
+ Result := Result + Chr(TextHexToDec(aText[i + 1] + aText[i + 2]));
+ i := Succ(Succ(i));
+ end
+ else
+ begin
+ if aText[i] = CPlus then
+ Result := (Result + CSpace)
+ else
+ Result := (Result + aText[i]);
+ end;
+ i := Succ(i);
+ end;
+end;
+
+{ Returns "file.ext" from "http://www.site.com/path/here/file.ext". }
+function TextURIExtractParams(const aURI: string): string;
+begin
+ Result := TextFetchRight(aURI, '?', True);
+end;
+
+{ Returns "http://www.site.com/path/here/" from "http://www.site.com/path/here/file.ext" }
+function TextURIWithoutParams(const aURI: string): string;
+var
+ rPrefix, rHost, rPath, rParams: string;
+begin
+ // Have to do everything here. If we go too deep on the stack
+ // Delphi forgets string refcount and returns nothing :S.
+ if (TextPos(aURI, CQuestionMark, True) > 0) then
+ Exit(TextFetchLeft(aURI, CQuestionMark, True))
+ else
+ Result := CEmpty;
+
+ if (TextURISplit(aURI, rPrefix, rHost, rPath, rParams)) then
+ Result := rPrefix + CURISchemeDelimiter + rHost + rPath;
+end;
+
+{ Returns a hex display style string from aData of aSize. }
+function TextDump(const aData: pByte; const aSize: integer; const aBytesPerLine: byte): string;
+var
+ p: pbyte;
+ i: integer;
+ h: string;
+ t: string;
+begin
+ if (aData = nil) or (aSize <= 0) or (aBytesPerLine = 0) then
+ Exit;
+
+ i := 0;
+ p := aData;
+ while (i < aSize) do
+ begin
+ if ((i mod aBytesPerLine = 0) and (i <> 0)) or (i = aSize) then
+ begin
+ Result := Result + h + CSpace + CMinus + CSpace + t + CCrLf;
+ h := CEmpty;
+ t := CEmpty;
+ end;
+
+ if (h <> CEmpty) then
+ begin
+ if (i mod 8 = 0) then
+ h := h + CSpace + CSpace
+ else
+ h := h + CSpace;
+ end;
+
+ h := h + IntToHex(p^, 2);
+ if (p^ >= 20) and (p^ <= 127) then
+ t := t + Chr(p^)
+ else
+ t := t + CDot;
+
+ Inc(p);
+ Inc(i);
+ end;
+
+ if (h <> CEmpty) then
+ begin
+ Result := Result + h;
+ while (i mod aBytesPerLine <> 0) do
+ begin
+ if (i mod 8 = 0) then
+ Result := Result + CSpace + CSpace + CSpace + CSpace
+ else
+ Result := Result + CSpace + CSpace + CSpace;
+ Inc(i);
+ end;
+ Result := Result + CSpace + CMinus + CSpace + t;
+ end;
+end;
+
+{ Save aText to aFileName. }
+procedure TextSave(const aText, aFileName: string);
+var
+ f: TextFile;
+begin
+ AssignFile(f, aFileName, 65001);
+ Rewrite(f);
+ write(f, aText);
+ CloseFile(f);
+end;
+
+{ Returns a string of length aLength composed entirely of aChar. }
+function TextOfChar(const aChar: char; const aLength: integer): string;
+var
+ i: integer;
+begin
+ if (aLength <= 0) then
+ Exit('');
+ SetLength(Result, alength);
+ for i := 1 to aLength do
+ Result[i] := aChar;
+end;
+
+{ Splits IRC hostmask nickname!ident@host.name into parts. }
+function SplitHostMask(const aHostMask: string; var aNickname, aIdent, aHost: string): boolean;
+begin
+ if (Length(aHostMask) = 0) then
+ Exit(False);
+
+ aHost := aHostMask;
+ aIdent := TextExtractLeft(aHost, CMonkey);
+ aNickname := TextExtractLeft(aIdent, CExclam);
+ Result := (aHost <> CEmpty) and (aIdent <> CEmpty) and (aNickname <> CEmpty);
+end;
+
+{ Returns a random number character. }
+function RandomNum: char;
+begin
+ Result := pchar(CNums)[Random(Length(CNums))];
+end;
+
+{ Returns a random string of number characters of aLength. }
+function RandomNums(const aLength: byte): string;
+var
+ i: Integer;
+begin
+ Result := CEmpty;
+
+ for i := 0 to aLength - 1 do
+ Result := Result + RandomNum;
+end;
+
+{ Returns a random lowercase letter. }
+function RandomAlphaLower: char;
+begin
+ Result := pchar(CAlphaLower)[Random(Length(CAlphaLower))];
+end;
+
+{ Returns a random string of lowercase letters of aLength. }
+function RandomAlphaLowers(const aLength: byte): string;
+var
+ i: Integer;
+begin
+ Result := CEmpty;
+
+ for i := 0 to aLength - 1 do
+ Result := Result + RandomAlphaLower;
+end;
+
+{ Returns a random uppercase letter. }
+function RandomAlphaUpper: char;
+begin
+ Result := pchar(CAlphaUpper)[Random(Length(CAlphaUpper))];
+end;
+
+{ Returns a random string of uppercase letters of aLength. }
+function RandomAlphaUppers(const aLength: byte): string;
+var
+ i: Integer;
+begin
+ Result := CEmpty;
+
+ for i := 0 to aLength - 1 do
+ Result := Result + RandomAlphaUpper;
+end;
+
+{ Returns a random lowercase vowel. }
+function RandomVowelLower: char;
+begin
+ Result := pchar(CVowelsLower)[Random(Length(CVowelsLower))];
+end;
+
+{ Returns a random uppercase vowel. }
+function RandomVowelUpper: char;
+begin
+ Result := pchar(CVowelsUpper)[Random(Length(CVowelsUpper))];
+end;
+
+{ Returns a random vowel. }
+function RandomVowel: char;
+begin
+ Result := pchar(CVowels)[Random(Length(CVowels))];
+end;
+
+{ Returns a random lowercase consonant. }
+function RandomConsonantLower: char;
+begin
+ Result := pchar(CConsonantsLower)[Random(Length(CConsonantsLower))];
+end;
+
+{ Returns a random uppercase consonant. }
+function RandomConsonantUpper: char;
+begin
+ Result := pchar(CConsonantsUpper)[Random(Length(CConsonantsUpper))];
+end;
+
+{ Returns a random consonant. }
+function RandomConsonant: char;
+begin
+ Result := pchar(CConsonants)[Random(Length(CConsonants))];
+end;
+
+{ Generates a random string of aLength. }
+function RandomString(const aLength: Integer; const aLowerCase, aUpperCase, aNumeric: boolean): string;
+type
+ TRandomFunc = function: char;
+ TRandomFuncs = array of TRandomFunc;
+var
+ i: Integer;
+ f: TRandomFuncs;
+begin
+ Result := CEmpty;
+
+ if (aLowerCase) then
+ begin
+ SetLength(f, Length(f) + 1);
+ f[Length(f) - 1] := RandomAlphaLower;
+ end;
+
+ if (aUpperCase) then
+ begin
+ SetLength(f, Length(f) + 1);
+ f[Length(f) - 1] := RandomAlphaUpper;
+ end;
+
+ if (aNumeric) then
+ begin
+ SetLength(f, Length(f) + 1);
+ f[Length(f) - 1] := RandomNum;
+ end;
+
+ for i := 0 to aLength - 1 do
+ Result := Result + f[Random(Length(f))];
+end;
+
+{ Returns an integer in range >= aMin and <= aMax. }
+function RandomRange(const aMin, aMax: Integer): Integer;
+begin
+ Result := Random(aMax - aMin) + aMin;
+end;
+
+{ Returns a random boolean. Fiddy fiddy bitch money dawg yo sup sup u down. }
+function RandomBool: boolean;
+begin
+ Result := (Random > 0.5);
+end;
+
+{ ======= }
+{ TTokens }
+{ ======= }
+
+{ GetEnumerator implement. }
+function TTokens.GetEnumerator: TTokensEnumerator;
+begin
+ Result := TTokensEnumerator.Create(Self);
+end;
+
+{ Returns tokens from and including token at aIndex as a string delimited by aDelimiter. }
+function TTokens.FromToken(const aIndex: Integer; const aDelimiter: string): string;
+var
+ i: Integer;
+begin
+ Result := CEmpty;
+
+ for i := aIndex to FCount - 1 do
+ begin
+ if (i = aIndex) then
+ Result := Result + GetToken(i)
+ else
+ Result := Result + aDelimiter + GetToken(i);
+ end;
+end;
+
+{ Returns tokens from start to and including token at aIndex as a string delimited by aDelimiter. }
+function TTokens.ToToken(const aIndex: Integer; const aDelimiter: string): string;
+var
+ i: Integer;
+begin
+ Result := CEmpty;
+
+ for i := 0 to aIndex do
+ begin
+ if (i = 0) then
+ Result := Result + GetToken(i)
+ else
+ Result := Result + aDelimiter + GetToken(i);
+ end;
+end;
+
+{ Adds a string to the array. }
+procedure TTokens.Add(const aText: string);
+begin
+ if (aText = CEmpty) then
+ Exit;
+ Inc(FCount);
+ SetLength(FTokens, FCount);
+ FTokens[FCount - 1] := aText;
+end;
+
+{ Adds aKey=aVal as one string to the array. String aVal overload. }
+procedure TTokens.Add(const aKey, aVal: string);
+begin
+ Add(aKey + '=' + aVal);
+end;
+
+{ Adds aKey=aVal as one string to the array. Integer aVal overload. }
+procedure TTokens.Add(const aKey: string; const aVal: integer);
+begin
+ Add(aKey, TextFromInt(aVal));
+end;
+
+{ Adds aKey=aVal as one string to the array. Boolean aVal overload. }
+procedure TTokens.Add(const aKey: string; const aVal: boolean);
+begin
+ Add(aKey, TextFromBool(aVal));
+end;
+
+{ Adds aKey="aVal" as one string to the array. String aVal overload. }
+procedure TTokens.AddQ(const aKey, aVal: string);
+begin
+ Add(aKey + '="' + aVal + '"');
+end;
+
+{ Adds aKey="aVal" as one string to the array. Integer aVal overload. }
+procedure TTokens.AddQ(const aKey: string; const aVal: integer);
+begin
+ Add(aKey + '="' + TextFromInt(aVal) + '"');
+end;
+
+{ Adds aKey="aVal" as one string to the array. Boolean aVal overload. }
+procedure TTokens.AddQ(const aKey: string; const aVal: boolean);
+begin
+ Add(aKey + '="' + TextFromBool(aVal) + '"');
+end;
+
+{ Returns all tokens in one string separated by aDelimiter. }
+function TTokens.AllTokens(const aDelimiter: string): string;
+var
+ i: Integer;
+begin
+ Result := CEmpty;
+
+ for i := 0 to FCount - 1 do
+ begin
+ if (i = 0) then
+ Result := Result + GetToken(i)
+ else
+ Result := Result + aDelimiter + GetToken(i);
+ end;
+end;
+
+{ Clears all tokens. }
+procedure TTokens.Clear;
+begin
+ SetLength(FTokens, 0);
+ Finalize(FTokens);
+ FCount := 0;
+end;
+
+{ Checks if empty. }
+function TTokens.Empty: boolean;
+begin
+ Result := (FCount = 0);
+end;
+
+{ Returns an array of string from and including token at aFromToken to and including token at aToToken. }
+function TTokens.ToArray(const aFromToken, aToToken: Integer): TArray;
+var
+ i: Integer;
+begin
+ if (aFromToken < 0) or (aFromToken >= FCount) or (aToToken < aFromToken) then
+ Exit;
+
+ SetLength(Result, FCount - (aToToken - aFromToken));
+
+ for i := aFromToken to aToToken do
+ Result[i] := Token[i];
+end;
+
+{ Token getter. Get as string. }
+function TTokens.GetToken(const aIndex: Integer): string;
+begin
+ if ((aIndex < 0) or (aIndex >= FCount)) then
+ Result := CEmpty
+ else
+ Result := FTokens[aIndex];
+end;
+
+{ Pair getter. Get as TPair. }
+function TTokens.GetPair(const aIndex: integer): TPair;
+begin
+ if ((aIndex < 0) or (aIndex >= FCount)) then
+ begin
+ Result.Key := '';
+ Result.Val := '';
+ end
+ else
+ begin
+ Result.Key := TextFetchLeft(FTokens[aIndex], '=', True);
+ Result.Val := TextFetchRight(FTokens[aIndex], '=', True, False);
+ end;
+end;
+
+{ Exchanges two items in tokens. }
+
+procedure TTokens.Exchange(aIndexA, aIndexB: Integer);
+var
+ temp: string;
+begin
+ temp := FTokens[aIndexB];
+ FTokens[aIndexB] := FTokens[aIndexA];
+ FTokens[aIndexA] := temp;
+end;
+
+{ QuickSorts tokens. }
+procedure TTokens.QuickSort(aStart, aEnd: Integer);
+var
+ a: Integer;
+ i: Integer;
+ j: Integer;
+ p: Integer;
+begin
+ if (FCount <= 1) then
+ Exit;
+ a := aStart;
+ repeat
+ i := a;
+ j := aEnd;
+ p := (a + aEnd) shr 1;
+ repeat
+ while (CompareText(FTokens[i], FTokens[p]) < 0) do
+ Inc(i);
+ while (CompareText(FTokens[j], FTokens[p]) > 0) do
+ Dec(j);
+ if (i <= j) then
+ begin
+ if (i <> j) then
+ Exchange(i, j);
+ if (p = i) then
+ p := j
+ else
+ if (p = j) then
+ p := i;
+ Inc(i);
+ Dec(j);
+ end;
+ until (i > j);
+ if (a < j) then
+ QuickSort(a, j);
+ a := i;
+ until (i >= aEnd);
+end;
+
+{ Sorts the items. }
+procedure TTokens.Sort;
+begin
+ QuickSort(0, FCount - 1);
+end;
+
+{ ================= }
+{ TTokensEnumerator }
+{ ================= }
+
+{ Constructor. }
+constructor TTokensEnumerator.Create(aTokens: TTokens);
+begin
+ inherited Create;
+ FIndex := - 1;
+ FTokens := aTokens;
+end;
+
+{ GetCurrent implementaiton. }
+function TTokensEnumerator.GetCurrent: string;
+begin
+ Result := FTokens[FIndex];
+end;
+
+{ MoveNext Implementation. }
+function TTokensEnumerator.MoveNext: Boolean;
+begin
+ Result := (FIndex < FTokens.Count - 1);
+ if Result then
+ Inc(FIndex);
+end;
+
+end.
diff --git a/EvilWorks.System.SysUtils.pas b/EvilWorks.System.SysUtils.pas
new file mode 100644
index 0000000..2826149
--- /dev/null
+++ b/EvilWorks.System.SysUtils.pas
@@ -0,0 +1,1061 @@
+//
+// EvilLibrary by Vedran Vuk 2010-2012
+//
+// Name: EvilWorks.System.SysUtils
+// Description: Stuff I'd like to see in Delphi's SysUtils. And more.
+// File last change date: October 1st. 2012
+// File version: Dev 0.0.0
+//
+
+unit EvilWorks.System.SysUtils;
+
+interface
+
+uses
+ WinApi.Windows,
+ WinApi.Messages,
+ System.SysUtils;
+
+{ Error retrieval }
+
+function GetErrorText(const aError: cardinal): string;
+function GetLastErrorText: string;
+
+{ Dialog boxes }
+
+procedure ShowMessage(const aMessage: string);
+procedure ShowInformation(const aInformation: string);
+procedure ShowWarning(const aWarning: string);
+procedure ShowError(const aError: string);
+procedure ShowLastError(const aCustomMessage: string = '');
+
+{ Window properties }
+
+function GetWindowFileName(const aWindow: HWND): string;
+function GetWindowCaption(const aWindow: HWND): string;
+function GetWindowClassName(const aWindow: HWND): string;
+function GetWindowShowState(const aWindow: HWND): integer;
+function GetWindowIcon(const aWindow: HWND; const aBigIcon: boolean = False): HICON;
+function GetWindowAppIcon(const aWindow: HWND; const aBigIcon: boolean = False): HICON;
+function GetWindowHeight(const aWindow: HWND): integer;
+function GetWindowWidth(const aWindow: HWND): integer;
+function SetWindowHeight(const aWindow: HWND; const aHeight: integer): boolean;
+function SetWindowWidth(const aWindow: HWND; const aWidth: integer): boolean;
+function IsWindowResizeable(const aWindow: HWND): integer;
+
+{ Window manipulation }
+
+function RestoreWindowWithoutAnimations(const aWindow: HWND): boolean;
+function FindChildWindow(const aParent: HWND; const aClsName, aWndName: string; const aID: integer): HWND;
+function GetFileVersion(const aFileName: string): string;
+
+{ Keyboard shortcut utilities }
+
+procedure SeparateShortcut(const aShortcut: cardinal; var aKey, aModifier: Word);
+function IsKeyPressed(aKey: Word): boolean;
+function IsModifierPressed(aModifier: Word): boolean;
+function KeyToText(aKey: Word): string;
+function ModifiersToText(aModifiers: Word): string;
+function ShortcutToText(const aKey, aModifiers: Word): string; overload;
+function ShortcutToText(const aShortcut: cardinal): string; overload;
+function IsShortcutReserved(const aModifiers, aKey: Word): boolean; overload;
+function IsShortcutReserved(const aShortcut: cardinal): boolean; overload;
+
+{ TODO: Sort us. }
+
+function NumElementsInSet(var aSet): Byte;
+
+function RandomRange(const aMin, aMax: integer): integer;
+function RandomBool: boolean;
+
+function HexToText(const aHexStr: string): string;
+function HexToDec(const aHexStr: string): cardinal;
+
+function BytesToFriendlyString(Value: Dword): string;
+function BitsToFriendlyString(Value: Dword): string;
+
+function GetSelfFileName: string;
+function GetSelfFileNameOnly: string;
+function GetSelfDir: string;
+function GetSelfPath: string;
+function GetWindowsDir: string;
+function GetWindowsPath: string;
+function GetSystemDir: string;
+function GetSystemPath: string;
+
+function RemoveExtension(const aFileName: string): string;
+function ExtractFileNameOnly(const aFileName: string): string;
+function ExtractFileDirOnly(const aFileName: string): string;
+function ExtractLastPathElement(const aFileName: string): string;
+function ExtractParentDir(const aFileName: string): string;
+function ExtractParentPath(const aFileName: string): string;
+
+function ExpandEnvironmentVariable(const aString: string): string;
+function ExpandEnvironmentVariables(const aString: string): string;
+
+function GetLayeredWindowAttributes(
+ HWND: HWND; var crKey: COLORREF; var bAlpha: byte; var dwFlags: DWORD
+ ): BOOL; stdcall; external user32 name 'GetLayeredWindowAttributes';
+
+function SetLayeredWindowAttributes(
+ HWND: HWND; crKey: COLORREF; bAlpha: byte; dwFlags: DWORD
+ ): BOOL; stdcall; external user32 name 'SetLayeredWindowAttributes';
+
+type
+ TOnOutput = procedure(const aOutput: string) of object;
+
+procedure RunConsoleApp(const aTarget, aParams, aRunIn: string; aOutputProc: TOnOutput);
+
+implementation
+
+uses
+ EvilWorks.System.StrUtils;
+
+{ Retrieves description for a specified Windows error. }
+function GetErrorText(const aError: cardinal): string;
+var
+ buffer: array [0 .. 255] of char;
+ flags : DWORD;
+begin
+ FillChar(buffer, 256, #0);
+ flags := FORMAT_MESSAGE_FROM_SYSTEM or FORMAT_MESSAGE_IGNORE_INSERTS or FORMAT_MESSAGE_ARGUMENT_ARRAY;
+ FormatMessage(flags, nil, aError, 0, buffer, SizeOf(buffer), nil);
+ Result := TextRemoveLineFeeds(buffer);
+end;
+
+{ Retrieves last Windows error description.}
+function GetLastErrorText: string;
+begin
+ Result := GetErrorText(WinApi.Windows.GetLastError);
+end;
+
+{ Displays a message dialog. }
+procedure ShowMessage(const aMessage: string);
+begin
+ MessageBox(0, PChar(aMessage), PChar(GetSelfFileName), MB_OK);
+end;
+
+{ Displays an information dialog. }
+procedure ShowInformation(const aInformation: string);
+begin
+ MessageBox(0, PChar(aInformation), PChar(GetSelfFileName), MB_ICONINFORMATION or MB_OK);
+end;
+
+{ Displays a warning dialog. }
+procedure ShowWarning(const aWarning: string);
+begin
+ MessageBox(0, PChar(aWarning), PChar(GetSelfFileName), MB_ICONWARNING or MB_OK);
+end;
+
+{ Displays an error dialog. }
+procedure ShowError(const aError: string);
+begin
+ MessageBox(0, PChar(aError), PChar(GetSelfFileName), MB_ICONERROR or MB_OK);
+end;
+
+{ Displays last windows error description with optional custom message. }
+procedure ShowLastError(const aCustomMessage: string = '');
+begin
+ if (aCustomMessage <> '') then
+ ShowError(aCustomMessage + #13#10#10#10 + GetLastErrorText)
+ else
+ ShowError(GetLastErrorText);
+end;
+
+{ GetWindowModuleFilename wrapper. }
+function GetWindowFileName(const aWindow: HWND): string;
+var
+ buf: PChar;
+ ret: integer;
+begin
+ Result := '';
+
+ buf := AllocMem(MAX_PATH + 1);
+ if (buf = nil) then
+ Exit;
+ try
+ ret := GetWindowModuleFileName(aWindow, buf, MAX_PATH);
+ SetString(Result, buf, ret);
+ finally
+ FreeMem(buf);
+ end
+end;
+
+{ Gets window caption. }
+function GetWindowCaption(const aWindow: HWND): string;
+var
+ buf: PChar;
+ ret: integer;
+begin
+ Result := '';
+
+ buf := AllocMem(MAX_PATH + 1);
+ if (buf = nil) then
+ Exit;
+ try
+ ret := GetWindowText(aWindow, buf, MAX_PATH);
+ SetString(Result, buf, ret);
+ finally
+ FreeMem(buf);
+ end;
+end;
+
+{ Gets window class name. }
+function GetWindowClassName(const aWindow: HWND): string;
+var
+ buf: PChar;
+ ret: integer;
+begin
+ Result := '';
+
+ buf := AllocMem(MAX_PATH + 1);
+ if (buf = nil) then
+ Exit;
+ try
+ ret := GetClassName(aWindow, buf, MAX_PATH);
+ SetString(Result, buf, ret);
+ finally
+ FreeMem(buf);
+ end;
+end;
+
+{ Gets window show state (SW_SHOW, SW_MINIMIZED, SW_MAXIMIZED...). Returns -1 if function failed. }
+function GetWindowShowState(const aWindow: HWND): integer;
+var
+ winPl: TWindowPlacement;
+begin
+ winPl.Length := SizeOf(winPl);
+ if (GetWindowPlacement(aWindow, winPl)) then
+ Result := winPl.showCmd
+ else
+ Result := - 1;
+end;
+
+{ Tries to retrieve the icon of a aWindow. }
+function GetWindowIcon(const aWindow: HWND; const aBigIcon: boolean = False): HICON;
+begin
+ if (aBigIcon) then
+ Result := SendMessage(aWindow, WM_GETICON, 1, 0)
+ else
+ Result := SendMessage(aWindow, WM_GETICON, 0, 0);
+end;
+
+{ Tries to retrieve the icon of the app that owns the aWindow. }
+function GetWindowAppIcon(const aWindow: HWND; const aBigIcon: boolean = False): HICON;
+begin
+ Result := 0;
+end;
+
+{ Gets window Height. - 1 on error. }
+function GetWindowHeight(const aWindow: HWND): integer;
+var
+ R: TRect;
+begin
+ if (GetWindowRect(aWindow, R)) then
+ Result := R.Height
+ else
+ Result := - 1;
+end;
+
+{ Gets window Width. - 1 on error. }
+function GetWindowWidth(const aWindow: HWND): integer;
+var
+ R: TRect;
+begin
+ if (GetWindowRect(aWindow, R)) then
+ Result := R.Width
+ else
+ Result := - 1;
+end;
+
+{ Sets window Height. }
+function SetWindowHeight(const aWindow: HWND; const aHeight: integer): boolean;
+var
+ w: integer;
+begin
+ w := GetWindowWidth(aWindow);
+ if (w <> - 1) then
+ Result := SetWindowPos(aWindow, 0, 0, 0, w, aHeight, SWP_NOMOVE or SWP_NOZORDER)
+ else
+ Result := False;
+end;
+
+{ Gets window Width. }
+function SetWindowWidth(const aWindow: HWND; const aWidth: integer): boolean;
+var
+ h: integer;
+begin
+ h := GetWindowHeight(aWindow);
+ if (h <> - 1) then
+ Result := SetWindowPos(aWindow, 0, 0, 0, aWidth, h, SWP_NOMOVE or SWP_NOZORDER)
+ else
+ Result := False;
+end;
+
+{ Tries to guess if the window has a sizeable border. Returns 1 if yes, 0 if no, -1 if error occured. }
+function IsWindowResizeable(const aWindow: HWND): integer;
+var
+ gwl: longint;
+ sb : HWND;
+begin
+ gwl := GetWindowLong(aWindow, GWL_STYLE);
+
+ if (gwl = 0) then
+ Exit( - 1);
+
+ if (gwl and WS_SIZEBOX <> 0) or (gwl and WS_THICKFRAME <> 0) then
+ Exit(1);
+
+ sb := FindWindowEx(aWindow, 0, 'ScrollBar', nil);
+ if (sb = 0) then
+ Exit(0);
+
+ gwl := GetWindowLong(sb, GWL_EXSTYLE);
+ if (gwl = 0) then
+ Exit( - 1);
+
+ if (gwl and SBS_SIZEGRIP <> 0) then
+ Result := 1
+ else
+ Result := 0;
+end;
+
+{ Recursively searches a window and its children for a child window. }
+function FindChildWindow(const aParent: HWND; const aClsName, aWndName: string; const aID: integer): HWND;
+// -----------------------------------------------------------------------------------------------------------
+//
+// Recursivy searches a window and its children for a window with a matching
+// ClassName, WindowName and ControlID. Any ommited parameters to be compared are
+// a match by default. If all three parameters are ommited, the first child
+// found is the result.
+//
+// aParent: HWND - Handle of the parent window to search.
+// aClassName: string - Class name of the child window to find.
+// aWindowName: string - Window name of the child window to find.
+// aID: integer - Dialog control ID of the child window to find.
+//
+// -----------------------------------------------------------------------------------------------------------
+type
+ TEnumChildRec = record
+ ClassName: string;
+ WindowName: string;
+ ControlID: integer;
+ ChildHandle: HWND;
+ end;
+
+ PEnumChildRec = ^TEnumChildRec;
+
+ function EnumChildProc(aHandle: HWND; aLParam: LPARAM): boolean; stdcall;
+ var
+ data : PEnumChildRec;
+ passClass: boolean;
+ passName : boolean;
+ passID : boolean;
+ begin
+ if (aHandle = 0) or (aLParam = 0) then
+ Exit(False);
+
+ data := PEnumChildRec(aLParam);
+ if ((data.ClassName = '') and (data.WindowName = '') and (data.ControlID = 0)) then
+ begin
+ data^.ChildHandle := aHandle;
+ Exit(False);
+ end;
+
+ if (data.ClassName = '') then
+ passClass := True
+ else
+ passClass := TextEquals(GetWindowClassName(aHandle), data^.ClassName);
+
+ if (data.WindowName = '') then
+ passName := True
+ else
+ passName := TextEquals(GetWindowCaption(aHandle), data^.WindowName);
+
+ if (data.ControlID = 0) then
+ passID := True
+ else
+ passID := GetDlgCtrlID(aHandle) = data.ControlID;
+
+ if (passClass and passName and passID) then
+ begin
+ data^.ChildHandle := aHandle;
+ Exit(False);
+ end
+ else
+ begin
+ data^.ChildHandle := FindChildWindow(aHandle, data^.ClassName, data^.WindowName, data^.ControlID);
+ if (data^.ChildHandle = 0) then
+ Result := True
+ else
+ Result := False;
+ end;
+ end;
+
+var
+ EnumChildRec: TEnumChildRec;
+begin
+ Result := 0;
+
+ EnumChildRec.ClassName := aClsName;
+ EnumChildRec.WindowName := aWndName;
+ EnumChildRec.ControlID := aID;
+ EnumChildRec.ChildHandle := 0;
+
+ EnumChildWindows(aParent, @EnumChildProc, LPARAM(@EnumChildRec));
+
+ if (EnumChildRec.ChildHandle <> 0) then
+ Result := EnumChildRec.ChildHandle;
+end;
+
+{ Restores a window without window animations (if enabled). }
+function RestoreWindowWithoutAnimations(const aWindow: HWND): boolean;
+var
+ ai : TAnimationInfo;
+ aiTemp: TAnimationInfo;
+begin
+ Result := False;
+
+ FillChar(ai, SizeOf(ai), 0);
+ ai.cbSize := SizeOf(ai);
+ if (SystemParametersInfo(SPI_GETANIMATION, SizeOf(ai), @ai, 0)) then
+ begin
+ if (ai.iMinAnimate <> 0) then
+ begin
+ FillChar(aiTemp, SizeOf(aiTemp), 0);
+ aiTemp.cbSize := SizeOf(aiTemp);
+ aiTemp.iMinAnimate := 0;
+ SystemParametersInfo(SPI_SETANIMATION, SizeOf(aiTemp), @aiTemp, 0);
+ end;
+
+ Result := ShowWindow(aWindow, SW_RESTORE);
+ if (ai.iMinAnimate <> 0) then
+ Result := Result and SystemParametersInfo(SPI_SETANIMATION, SizeOf(ai), @ai, 0);
+ end;
+end;
+
+{ Gets executable file version info }
+function GetFileVersion(const aFileName: string): string;
+var
+ VerInfoSize : DWORD;
+ VerInfo : Pointer;
+ VerValueSize: DWORD;
+ VerValue : PVSFixedFileInfo;
+ Dummy : DWORD;
+ s : shortstring;
+begin
+ Result := '';
+ VerInfoSize := GetFileVersionInfoSize(PChar(aFileName), Dummy);
+ if (VerInfoSize = 0) then
+ Exit;
+ GetMem(VerInfo, VerInfoSize);
+ GetFileVersionInfo(PChar(aFileName), 0, VerInfoSize, VerInfo);
+ VerQueryValue(VerInfo, '\', Pointer(VerValue), VerValueSize);
+ with VerValue^ do
+ begin
+ Str(dwFileVersionMS shr 16, s);
+ Result := string(s);
+ Str(dwFileVersionMS and $FFFF, s);
+ Result := Result + '.' + string(s);
+ Str(dwFileVersionLS shr 16, s);
+ Result := Result + '.' + string(s);
+ Str(dwFileVersionLS and $FFFF, s);
+ Result := Result + '.' + string(s);
+ end;
+ FreeMem(VerInfo, VerInfoSize);
+end;
+
+{ Separates aShortcut into aKey and aModifier parts. }
+procedure SeparateShortcut(const aShortcut: cardinal; var aKey, aModifier: Word);
+begin
+ aKey := Word(aShortcut);
+ aModifier := HiWord(aShortcut);
+end;
+
+{ Checks if aKey on the keyboard is pressed. }
+function IsKeyPressed(aKey: Word): boolean;
+begin
+ Result := (GetAsyncKeyState(aKey) and (1 shl 15) <> 0);
+end;
+
+{ Checks if keyboard modifier (MOD_SHIFT, MOD_CTRL, MOD_ALT, MOD_WIN) is pressed. }
+function IsModifierPressed(aModifier: Word): boolean;
+begin
+ Result := False;
+
+ case aModifier of
+
+ MOD_SHIFT:
+ Result := (IsKeyPressed(VK_LSHIFT) or IsKeyPressed(VK_RSHIFT) or IsKeyPressed(VK_SHIFT));
+
+ MOD_CONTROL:
+ Result := (IsKeyPressed(VK_LCONTROL) or IsKeyPressed(VK_RCONTROL) or IsKeyPressed(VK_CONTROL));
+
+ MOD_ALT:
+ Result := (IsKeyPressed(VK_LMENU) or IsKeyPressed(VK_RMENU) or IsKeyPressed(VK_MENU));
+
+ MOD_WIN:
+ Result := (IsKeyPressed(VK_LWIN) or IsKeyPressed(VK_RWIN) or IsKeyPressed(VK_APPS));
+
+ end; { case }
+end;
+
+{ Returns a text representation of a keyboard key in current system locale. }
+function KeyToText(aKey: Word): string;
+
+ function LocalIsExtendedKey(Key: Word): boolean;
+ begin
+ Result := ((Key >= VK_BROWSER_BACK) and (Key <= VK_LAUNCH_APP2)) or (aKey in [VK_LWIN, VK_RWIN]);
+ end;
+
+ function LocalGetExtendedVKName(aKey: Word): string;
+ begin
+ case aKey of
+
+ VK_LWIN, VK_RWIN:
+ Result := 'Win';
+
+ VK_BROWSER_BACK:
+ Result := 'Browser Back';
+
+ VK_BROWSER_FORWARD:
+ Result := 'Browser Forward';
+
+ VK_BROWSER_REFRESH:
+ Result := 'Browser Refresh';
+
+ VK_BROWSER_STOP:
+ Result := 'Browser Stop';
+
+ VK_BROWSER_SEARCH:
+ Result := 'Browser Search';
+
+ VK_BROWSER_FAVORITES:
+ Result := 'Browser Favorites';
+
+ VK_BROWSER_HOME:
+ Result := 'Browser Home';
+
+ VK_VOLUME_MUTE:
+ Result := 'Volume Mute';
+
+ VK_VOLUME_DOWN:
+ Result := 'Volume Down';
+
+ VK_VOLUME_UP:
+ Result := 'Volume Up';
+
+ VK_MEDIA_NEXT_TRACK:
+ Result := 'Media Next Track';
+
+ VK_MEDIA_PREV_TRACK:
+ Result := 'Media Prev Track';
+
+ VK_MEDIA_STOP:
+ Result := 'Media Stop';
+
+ VK_MEDIA_PLAY_PAUSE:
+ Result := 'Media Play/Pause';
+
+ VK_LAUNCH_MAIL:
+ Result := 'Media Launch Mail';
+
+ VK_LAUNCH_MEDIA_SELECT:
+ Result := 'Media Sect';
+
+ VK_LAUNCH_APP1:
+ Result := 'Media Launch App 1';
+
+ VK_LAUNCH_APP2:
+ Result := 'Media Launch App 2';
+
+ else
+ Result := '';
+
+ end; { case }
+ end;
+
+ function LocalGetVKName(aSpecial: boolean): string;
+ var
+ ScanCode: cardinal;
+ KeyName : array [0 .. 255] of char;
+ begin
+ Result := '';
+ if (aSpecial) then
+ ScanCode := (MapVirtualKey(byte(aKey), 0) shl 16) or (1 shl 24)
+ else
+ ScanCode := (MapVirtualKey(byte(aKey), 0) shl 16);
+
+ if (ScanCode <> 0) then
+ if (GetKeyNameText(ScanCode, KeyName, 255) <> 0) then
+ Result := KeyName;
+
+ if (Length(Result) <= 1) then
+ if (LocalIsExtendedKey(aKey)) then
+ Result := LocalGetExtendedVKName(aKey);
+ end;
+
+var
+ KeyName: string;
+begin
+ case byte(aKey) of
+ $21 .. $28, $2D, $2E:
+ KeyName := LocalGetVKName(True);
+ else
+ KeyName := LocalGetVKName(False);
+ end;
+ Result := KeyName;
+end;
+
+{ Returns modifiers in a format for HotKey controls: "[Modifier1 + [Modifier2 + ]"... }
+function ModifiersToText(aModifiers: Word): string;
+const
+ SPlus = ' + ';
+begin
+ if (aModifiers and MOD_SHIFT <> 0) then
+ Result := Result + KeyToText(VK_SHIFT) + SPlus;
+ if (aModifiers and MOD_CONTROL <> 0) then
+ Result := Result + KeyToText(VK_CONTROL) + SPlus;
+ if (aModifiers and MOD_ALT <> 0) then
+ Result := Result + KeyToText(VK_MENU) + SPlus;
+ if (aModifiers and MOD_WIN <> 0) then
+ Result := Result + KeyToText(VK_LWIN) + SPlus;
+end;
+
+{ Translates a keyboard shortcut to text. }
+function ShortcutToText(const aKey, aModifiers: Word): string;
+begin
+ if (aKey = 0) and (aModifiers = 0) then
+ begin
+ Result := '(none)';
+ Exit;
+ end;
+ Result := ModifiersToText(aModifiers);
+ Result := Result + KeyToText(aKey);
+end;
+
+{ Translates a keyboard shortcut to text. }
+function ShortcutToText(const aShortcut: cardinal): string; overload;
+var
+ Key : Word;
+ Modifiers: Word;
+begin
+ SeparateShortcut(aShortcut, Key, Modifiers);
+ Result := ShortcutToText(Key, Modifiers);
+end;
+
+{ Checks if a shortcut is already registered by some application. }
+function IsShortcutReserved(const aModifiers, aKey: Word): boolean;
+var
+ tempAtom: Word;
+begin
+ tempAtom := GlobalAddAtom(PChar('EvilWorks.HotkeyRegistrationTest'));
+ Result := RegisterHotKey(0, tempAtom, aModifiers, aKey);
+ if (Result) then
+ UnregisterHotKey(0, tempAtom);
+ GlobalDeleteAtom(tempAtom);
+ Result := (not Result);
+end;
+
+{ Checks if a shortcut is already registered by some application. }
+function IsShortcutReserved(const aShortcut: cardinal): boolean;
+var
+ tempKey : Word;
+ tempModifiers: Word;
+begin
+ SeparateShortcut(aShortcut, tempKey, tempModifiers);
+ Result := IsShortcutReserved(tempModifiers, tempKey);
+end;
+
+{ }
+function NumElementsInSet(var aSet): Byte;
+var
+ Mask: cardinal;
+begin
+ Mask := $80000000;
+ Result := 0;
+ while (Mask <> 0) do
+ begin
+ if ((cardinal(aSet) and Mask) <> 0) then
+ Inc(Result);
+ Mask := Mask shr 1;
+ end;
+end;
+
+{ }
+function RandomRange(const aMin, aMax: integer): integer;
+begin
+ if (aMin > aMax) then
+ Result := Random(aMin - aMax) + aMax
+ else
+ Result := Random(aMax - aMin) + aMin;
+end;
+
+{ }
+function RandomBool: boolean;
+begin
+ Result := (Random > 0.5);
+end;
+
+{ }
+function HexToText(const aHexStr: string): string;
+const
+ HexChars = [#$30 .. #$39] + [#$41 .. #$46] + [#$61 .. #$66];
+ HexNums = [$30 .. $39];
+ HexCharsLo = [$41 .. $46];
+ HexCharsHi = [$61 .. $66];
+var
+ InStr : ansistring;
+ i : integer;
+ Len : integer;
+ B : Byte;
+ OutByte: Byte;
+begin
+ InStr := ansistring(aHexStr);
+ i := 1;
+ while (i <= Length(InStr)) do
+ begin
+ if (InStr[i] in HexChars = False) then
+ Delete(InStr, i, 1)
+ else
+ Inc(i);
+ end;
+
+ Len := Length(InStr);
+ if (Len = 0) then
+ Exit;
+ if (Odd(Len)) then
+ begin
+ InStr := InStr + '0';
+ Inc(Len);
+ end;
+
+ i := 1;
+ while (i <= Len) do
+ begin
+ B := Byte(InStr[i + 0]);
+ if (B in HexNums) then
+ B := B - $30
+ else
+ if (B in HexCharsLo) then
+ B := B - $41 + $0A
+ else
+ if (B in HexCharsHi) then
+ B := B - $61 + $0A;
+ OutByte := 16 * B;
+
+ B := Byte(InStr[i + 1]);
+ if (B in HexNums) then
+ B := B - $30
+ else
+ if (B in HexCharsLo) then
+ B := B - $41 + $0A
+ else
+ if (B in HexCharsHi) then
+ B := B - $61 + $0A;
+ OutByte := OutByte + B;
+
+ Result := Result + Chr(OutByte);
+ Inc(i, 2);
+ end;
+end;
+
+{ }
+function HexToDec(const aHexStr: string): cardinal;
+var
+ c: cardinal;
+ B: Byte;
+begin
+ Result := 0;
+ if (Length(aHexStr) <> 0) then
+ begin
+ c := 1;
+ B := Length(aHexStr) + 1;
+ repeat
+ dec(B);
+ if (aHexStr[B] <= '9') then
+ Result := (Result + (cardinal(aHexStr[B]) - 48) * c)
+ else
+ Result := (Result + (cardinal(aHexStr[B]) - 55) * c);
+
+ c := c * 16;
+ until (B = 1);
+ end;
+end;
+
+{ }
+function BytesToFriendlyString(Value: Dword): string;
+const
+ OneKB = 1024;
+ OneMB = OneKB * 1024;
+ OneGB = OneMB * 1024;
+begin
+ if Value < OneKB then
+ Result := FormatFloat('#,##0.00 B', Value)
+ else
+ if Value < OneMB then
+ Result := FormatFloat('#,##0.00 KB', Value / OneKB)
+ else
+ if Value < OneGB then
+ Result := FormatFloat('#,##0.00 MB', Value / OneMB)
+end;
+
+{ }
+function BitsToFriendlyString(Value: Dword): string;
+const
+ OneKB = 1000;
+ OneMB = OneKB * 1000;
+ OneGB = OneMB * 1000;
+begin
+ if Value < OneKB then
+ Result := FormatFloat('#,##0.00 bps', Value)
+ else
+ if Value < OneMB then
+ Result := FormatFloat('#,##0.00 Kbps', Value / OneKB)
+ else
+ if Value < OneGB then
+ Result := FormatFloat('#,##0.00 Mbps', Value / OneMB)
+end;
+
+{ Returns a full path for this executable or dll. }
+function GetSelfFileName: string;
+var
+ buffer: array [0 .. MAX_PATH] of char;
+begin
+ ZeroMemory(@buffer, Length(buffer) * SizeOf(char));
+ if (GetModuleFileName(HInstance, buffer, MAX_PATH) > 0) then
+ Result := string(buffer)
+ else
+ Result := '';
+end;
+
+{ }
+function GetSelfFileNameOnly: string;
+begin
+ Result := ExtractFileNameOnly(GetSelfFileName);
+end;
+
+{ }
+function GetSelfDir: string;
+begin
+ Result := ExtractFileDir(GetSelfFileName);
+end;
+
+{ }
+function GetSelfPath: string;
+begin
+ Result := ExtractFilePath(GetSelfFileName);
+end;
+
+{ }
+function GetWindowsDir: string;
+var
+ Buffer: array [0 .. MAX_PATH] of char;
+begin
+ ZeroMemory(@Buffer, MAX_PATH + 2);
+ if (GetWindowsDirectory(Buffer, MAX_PATH) > 0) then
+ begin
+ Result := Buffer;
+ end;
+end;
+
+{ }
+function GetWindowsPath: string;
+begin
+ Result := IncludeTrailingPathDelimiter(GetWindowsDir);
+end;
+
+{ }
+function GetSystemDir: string;
+var
+ Buffer: array [0 .. MAX_PATH] of char;
+begin
+ ZeroMemory(@Buffer, MAX_PATH + 2);
+ if (GetSystemDirectory(Buffer, MAX_PATH) > 0) then
+ begin
+ Result := Buffer;
+ end;
+end;
+
+{ }
+function GetSystemPath: string;
+begin
+ Result := IncludeTrailingPathDelimiter(GetSystemDir);
+end;
+
+{ }
+function RemoveExtension(const aFileName: string): string;
+var
+ i: integer;
+begin
+ i := Length(aFileName);
+ while (i >= 1) and (aFileName[i] <> '.') do
+ dec(i);
+ if (i > 0) then
+ Result := TextLeft(aFileName, i - 1)
+ else
+ Result := aFileName;
+end;
+
+{ }
+function ExtractFileNameOnly(const aFileName: string): string;
+begin
+ Result := RemoveExtension(ExtractFileName(aFileName));
+end;
+
+{ }
+function ExtractFileDirOnly(const aFileName: string): string;
+begin
+
+end;
+
+{ }
+function ExtractLastPathElement(const aFileName: string): string;
+var
+ tokens: TTokens;
+begin
+ Result := '';
+ tokens := TextTokenize(aFileName, PathDelim);
+ Result := tokens[tokens.Count - 1];
+end;
+
+{ Gets parent directory of a filesystem object (dir, path or file). }
+function ExtractParentDir(const aFileName: string): string;
+begin
+ if (TextEnds(aFileName, PathDelim)) then
+ Result := ExtractFileDir(aFileName);
+ Result := ExtractFileDir(Result);
+end;
+
+{ Gets parent directory of a filesystem object (dir, path or file). }
+function ExtractParentPath(const aFileName: string): string;
+begin
+ Result := IncludeTrailingPathDelimiter(ExtractParentDir(aFileName));
+end;
+
+{ Expands an environment variable. }
+function ExpandEnvironmentVariable(const aString: string): string;
+var
+ Buffer: PChar;
+ Ret : cardinal;
+begin
+ Buffer := AllocMem(MAX_PATH + 1);
+ if (TextEnclosed(aString, CPercent, True)) then
+ Ret := GetEnvironmentVariable(PChar(TextUnEnclose(aString, CPercent, True)), Buffer, MAX_PATH + 1)
+ else
+ Ret := GetEnvironmentVariable(PChar(aString), Buffer, MAX_PATH + 1);
+ if (Ret <> 0) then
+ Result := Buffer
+ else
+ Result := CEmpty;
+ FreeMem(Buffer, MAX_PATH + 1);
+end;
+
+{ Expands all % enclosed environment variables in the aString. }
+function ExpandEnvironmentVariables(const aString: string): string;
+var
+ s: string;
+ v: string;
+ i: integer;
+begin
+ s := aString;
+ i := 0;
+ while (True) do
+ begin
+ v := TextFindEnclosed(s, CPercent, i, False, True);
+ if (v <> CEmpty) then
+ s := TextReplace(s, v, ExpandEnvironmentVariable(v), True)
+ else
+ Break;
+ Inc(i);
+ end;
+ Result := s;
+end;
+
+{ Runs a console application capturing its output. }
+procedure RunConsoleApp(const aTarget, aParams, aRunIn: string; aOutputProc: TOnOutput);
+const
+ READ_BUFFER_SIZE = 1024 * SizeOf(char);
+var
+ secAttribs : TSecurityAttributes;
+ startupInfo: TStartUpInfo;
+ processInfo: TProcessInformation;
+ Buffer : array [0 .. READ_BUFFER_SIZE - 1] of ansichar;
+ readPipe : THandle;
+ writePipe : THandle;
+ bytesRead : Dword;
+ appRunning : Dword;
+ cmdLine : string;
+ msg : TMsg;
+begin
+ { Create Read/Write pipes for child process. }
+ ZeroMemory(@secAttribs, SizeOf(secAttribs));
+ secAttribs.nLength := SizeOf(secAttribs);
+ secAttribs.lpSecurityDescriptor := nil;
+ secAttribs.bInheritHandle := True;
+ if (CreatePipe(readPipe, writePipe, @secAttribs, 0) = False) then
+ Exit;
+
+ { Create startup info. }
+ ZeroMemory(@startupInfo, SizeOf(startupInfo));
+ startupInfo.cb := SizeOf(startupInfo);
+ startupInfo.hStdError := writePipe;
+ startupInfo.hStdOutput := writePipe;
+ startupInfo.hStdInput := readPipe;
+ startupInfo.dwFlags := STARTF_USESTDHANDLES + STARTF_USESHOWWINDOW;
+ startupInfo.wShowWindow := SW_HIDE;
+
+ ZeroMemory(@processInfo, SizeOf(processInfo));
+
+ { Format cmdLine string. }
+ if (TextEnclosed(aTarget, CDoubleQuote, True)) then
+ cmdLine := aTarget
+ else
+ cmdLine := TextQuote(aTarget);
+
+ if (aParams <> CEmpty) then
+ cmdLine := TextQuote(CBackSlash + cmdLine + CSpace + aParams)
+ else
+ cmdLine := TextQuote(CBackSlash + cmdLine);
+
+ if (CreateProcess(nil, PChar(aTarget + CSpace + aParams), @secAttribs, @secAttribs, True, NORMAL_PRIORITY_CLASS, nil, nil, startupInfo, processInfo)) then
+ begin
+ repeat
+ appRunning := WaitForSingleObject(processInfo.hProcess, 0);
+
+ if (PeekMessage(msg, 0, 0, 0, PM_REMOVE)) then
+ begin
+ TranslateMessage(msg);
+ DispatchMessage(msg);
+ end;
+
+ repeat
+ bytesRead := 0;
+ PeekNamedPipe(readPipe, nil, 0, nil, @bytesRead, nil);
+ if (bytesRead > 0) then
+ begin
+ ReadFile(readPipe, Buffer[0], READ_BUFFER_SIZE, bytesRead, nil);
+ if (bytesRead <> 0) then
+ begin
+ Buffer[bytesRead] := #0;
+
+ OemToAnsi(Buffer, Buffer);
+ if (bytesRead <> 0) and (Assigned(aOutputProc)) then
+ aOutputProc(string(Buffer));
+ end;
+ end;
+ until (bytesRead = 0);
+
+ SleepEx(1, True);
+
+ until (appRunning <> WAIT_TIMEOUT);
+
+ CloseHandle(processInfo.hProcess);
+ CloseHandle(processInfo.hThread);
+ end;
+
+ CloseHandle(readPipe);
+ CloseHandle(writePipe);
+end;
+
+end.
diff --git a/EvilWorks.System.Xml.pas b/EvilWorks.System.Xml.pas
new file mode 100644
index 0000000..f3725ab
--- /dev/null
+++ b/EvilWorks.System.Xml.pas
@@ -0,0 +1,1026 @@
+(*============================================================================================================
+
+ EvilLibrary by Vedran Vuk 2010-2012
+
+ Name: EvilWorks.Xml
+ Description: Barebones Xml class. Don't expect it to follow standards. It parses XML, ok.
+ File last change date: August 11th. 2012
+ File version: 0.0.1
+ Licence: Free as in beer.
+
+ ===========================================================================================================*)
+
+unit EvilWorks.System.Xml;
+
+interface
+
+uses
+ System.Classes,
+ System.SysUtils,
+ EvilWorks.System.StrUtils;
+
+const
+ SAttributeNotFound = 'Attribute "%s" not found.';
+ SNodeNotFound = 'Node "%s" not found.';
+ SMalformedXml = 'Malformed XML on line %d.';
+ SCantHaveTextAndChildren = 'Node cannot have text and child nodes.';
+
+type
+ { Exceptions }
+ EXml = class(Exception);
+ EMalformedXml = class(EXml);
+ EAttributeNotFound = class(EXml);
+ ENodeNotFound = class(EXml);
+
+ { Forward declarations }
+ TXmlAttribute = class;
+ TXmlAttributes = class;
+ TXmlNode = class;
+ TXmlNodes = class;
+ TXml = class;
+
+ { TXmlAttribute }
+ TXmlAttribute = class(TPersistent)
+ private
+ FOwner: TXmlAttributes;
+
+ FName : string;
+ FValue: string;
+ procedure SetName(const aValue: string);
+ procedure SetValue(const aValue: string);
+ public
+ constructor Create(aOwner: TXmlAttributes); virtual;
+ procedure Assign(aSource: TPersistent); override;
+
+ property Owner: TXmlAttributes read FOwner;
+
+ property name: string read FName write SetName;
+ property Value: string read FValue write SetValue;
+ end;
+
+ { TXmlAttributes }
+ TXmlAttributes = class(TPersistent)
+ private
+ FOwner: TXmlNode;
+
+ FList: TList;
+ function GetCount: integer;
+ function GetByIndex(const aIndex: integer): TXmlAttribute;
+ function GetByName(const aName: string): TXmlAttribute;
+ procedure SetByName(const aName: string; const aValue: TXmlAttribute);
+ procedure SetByIndex(const aIndex: integer; const aValue: TXmlAttribute);
+ protected
+ function Add: TXmlAttribute; overload;
+ public
+ constructor Create(aOwner: TXmlNode); virtual;
+ destructor Destroy; override;
+ procedure Assign(aSource: TPersistent); override;
+
+ property Owner: TXmlNode read FOwner;
+
+ procedure Add(const aName, aValue: string); overload;
+ procedure Insert(const aName, aValue: string; const aIndex: integer);
+ procedure Delete(const aName: string); overload;
+ procedure Delete(const aIndex: integer); overload;
+ procedure Clear;
+ procedure Exchange(const aIndexA, aIndexB: integer);
+ procedure Move(const aFromIdx, aToIdx: integer);
+ function First: TXmlAttribute;
+ function Last: TXmlAttribute;
+ function Find(const aName: string): TXmlAttribute;
+ function IndexOf(const aName: string): integer; overload;
+ function IndexOf(aAttribute: TXmlAttribute): integer; overload;
+ function AttributeExists(const aName: string): boolean;
+
+ property Attributes[const aName: string]: TXmlAttribute read GetByName write SetByName;
+ property Items[const aIndex: integer]: TXmlAttribute read GetByIndex write SetByIndex; default;
+ property Count: integer read GetCount;
+ end;
+
+ { TXmlNode }
+ TXmlNode = class(TPersistent)
+ private
+ FOwner: TXmlNodes;
+
+ FText : string;
+ FAttributes: TXmlAttributes;
+ FName : string;
+ FNodes : TXmlNodes;
+ procedure SetText(const aValue: string);
+ procedure SetAttributes(const aValue: TXmlAttributes);
+ procedure SetName(const aValue: string);
+ procedure SetNodes(const aValue: TXmlNodes);
+ public
+ constructor Create(aOwner: TXmlNodes); virtual;
+ destructor Destroy; override;
+ procedure Assign(aSource: TPersistent); override;
+
+ property Owner: TXmlNodes read FOwner;
+ published
+ property Attributes: TXmlAttributes read FAttributes write SetAttributes;
+ property Nodes : TXmlNodes read FNodes write SetNodes;
+ property name : string read FName write SetName;
+ property Text : string read FText write SetText;
+ end;
+
+ { TXmlNodes }
+ TXmlNodes = class(TPersistent)
+ private
+ FOwner: TXmlNode;
+
+ FList: TList;
+ function GetByIndex(const aIndex: integer): TXmlNode;
+ function GetByName(const aName: string): TXmlNode;
+ function GetCount: integer;
+ procedure SetByIndex(const aIndex: integer; const aValue: TXmlNode);
+ procedure SetByName(const aName: string; const aValue: TXmlNode);
+ protected
+ function Add: TXmlNode; overload;
+ public
+ constructor Create(aOwner: TXmlNode); virtual;
+ destructor Destroy; override;
+ procedure Assign(aSource: TPersistent); override;
+
+ property Owner: TXmlNode read FOwner;
+
+ function Add(const aName: string; aText: string = CEmpty): TXmlNode; overload;
+ function Insert(const aName, aText: string; const aIndex: integer): TXmlNode;
+ procedure Delete(const aName: string); overload;
+ procedure Delete(const aIndex: integer); overload;
+ procedure Clear;
+ procedure Exchange(const aIndexA, aIndexB: integer);
+ procedure Move(const aFromIdx, aToIdx: integer);
+ function First: TXmlNode;
+ function Last: TXmlNode;
+ function Find(const aName: string): TXmlNode;
+ function IndexOf(const aName: string): integer; overload;
+ function IndexOf(aNode: TXmlNode): integer; overload;
+ function NodeExists(const aName: string): boolean;
+
+ property Nodes[const aName: string]: TXmlNode read GetByName write SetByName;
+ property Items[const aIndex: integer]: TXmlNode read GetByIndex write SetByIndex; default;
+ property Count: integer read GetCount;
+ end;
+
+ { TXmlHeader }
+ TXmlHeader = class(TPersistent)
+ private
+ FAttributes: TXmlAttributes;
+ procedure SetAttributes(const aValue: TXmlAttributes);
+ public
+ constructor Create; virtual;
+ destructor Destroy; override;
+ procedure Assign(aSource: TPersistent); override;
+
+ property Attributes: TXmlAttributes read FAttributes write SetAttributes;
+ end;
+
+ { TXml }
+ TXml = class(TPersistent)
+ private
+ FHeader : TXmlHeader;
+ FRoot : TXmlNode;
+ FIndentString: string;
+ procedure SetRoot(const aValue: TXmlNode);
+ procedure SetIndentString(const aValue: string);
+ procedure SetHeader(const aValue: TXmlHeader);
+ protected
+ procedure Malformed(const aLine: integer);
+ procedure Parse(aReader: TStreamReader);
+ procedure Serialize(aWriter: TStreamWriter);
+ public
+ constructor Create; virtual;
+ destructor Destroy; override;
+ procedure Assign(aSource: TPersistent); override;
+
+ procedure Clear;
+
+ procedure LoadFromFile(const aFileName: string);
+ procedure LoadFromStream(aStream: TStream);
+ procedure SaveToFile(const aFileName: string);
+ procedure SaveToStream(aStream: TStream);
+
+ property Header: TXmlHeader read FHeader write SetHeader;
+ property Root: TXmlNode read FRoot write SetRoot;
+ property IndentString: string read FIndentString write SetIndentString;
+ end;
+
+implementation
+
+{ TXmlAttribute }
+
+constructor TXmlAttribute.Create(aOwner: TXmlAttributes);
+begin
+ FOwner := aOwner;
+end;
+
+procedure TXmlAttribute.Assign(aSource: TPersistent);
+begin
+ if (aSource is TXmlAttribute) then
+ begin
+ name := TXmlAttribute(aSource).name;
+ Value := TXmlAttribute(aSource).Value;
+ end;
+end;
+
+procedure TXmlAttribute.SetName(const aValue: string);
+begin
+ if (FName = aValue) then
+ Exit;
+ FName := aValue;
+end;
+
+procedure TXmlAttribute.SetValue(const aValue: string);
+begin
+ if (FValue = aValue) then
+ Exit;
+ FValue := aValue;
+end;
+
+{ TXmlAttributes }
+
+constructor TXmlAttributes.Create(aOwner: TXmlNode);
+begin
+ FOwner := aOwner;
+
+ FList := TList.Create;
+end;
+
+destructor TXmlAttributes.Destroy;
+begin
+ Clear;
+ FList.Free;
+ inherited;
+end;
+
+procedure TXmlAttributes.Assign(aSource: TPersistent);
+var
+ i: integer;
+begin
+ if (aSource is TXmlAttributes) then
+ begin
+ Self.Clear;
+ for i := 0 to TXmlAttributes(aSource).Count - 1 do
+ Self.Add.Assign(TXmlAttributes(aSource).Items[i]);
+ end;
+end;
+
+function TXmlAttributes.Add: TXmlAttribute;
+begin
+ Result := TXmlAttribute.Create(Self);
+ FList.Add(Result);
+end;
+
+procedure TXmlAttributes.Add(const aName, aValue: string);
+begin
+ Insert(aName, aValue, FList.Count);
+end;
+
+procedure TXmlAttributes.Insert(const aName, aValue: string; const aIndex: integer);
+var
+ attr: TXmlAttribute;
+begin
+ attr := TXmlAttribute.Create(Self);
+ attr.name := aName;
+ attr.Value := aValue;
+ FList.Insert(aIndex, attr);
+end;
+
+procedure TXmlAttributes.Delete(const aName: string);
+var
+ i: integer;
+begin
+ i := IndexOf(aName);
+ if (i = - 1) then
+ raise EAttributeNotFound.CreateFmt(SAttributeNotFound, [aName]);
+
+ TXmlAttribute(FList[i]).Free;
+ FList.Delete(i);
+end;
+
+procedure TXmlAttributes.Delete(const aIndex: integer);
+begin
+ TXmlAttribute(FList[aIndex]).Free;
+ FList.Delete(aIndex);
+end;
+
+procedure TXmlAttributes.Clear;
+var
+ i: integer;
+begin
+ for i := FList.Count - 1 downto 0 do
+ begin
+ TXmlAttribute(FList[i]).Free;
+ FList.Delete(i);
+ end;
+end;
+
+procedure TXmlAttributes.Exchange(const aIndexA, aIndexB: integer);
+begin
+ FList.Exchange(aIndexA, aIndexB);
+end;
+
+procedure TXmlAttributes.Move(const aFromIdx, aToIdx: integer);
+begin
+ FList.Move(aFromIdx, aToIdx);
+end;
+
+function TXmlAttributes.Find(const aName: string): TXmlAttribute;
+var
+ i: integer;
+begin
+ Result := nil;
+
+ for i := 0 to FList.Count - 1 do
+ if (SameText(TXmlAttribute(FList[i]).name, aName)) then
+ Exit(TXmlAttribute(FList[i]));
+end;
+
+function TXmlAttributes.IndexOf(const aName: string): integer;
+var
+ i: integer;
+begin
+ Result := - 1;
+
+ for i := 0 to FList.Count - 1 do
+ if (SameText(TXmlAttribute(FList[i]).name, aName)) then
+ Exit(i);
+end;
+
+function TXmlAttributes.AttributeExists(const aName: string): boolean;
+begin
+ Result := (IndexOf(aName) > - 1);
+end;
+
+function TXmlAttributes.IndexOf(aAttribute: TXmlAttribute): integer;
+var
+ i: integer;
+begin
+ Result := - 1;
+
+ for i := 0 to FList.Count - 1 do
+ if (TXmlAttribute(FList[i]) = aAttribute) then
+ Exit(i);
+end;
+
+function TXmlAttributes.First: TXmlAttribute;
+begin
+ if (FList.Count = 0) then
+ Exit(nil);
+
+ Result := TXmlAttribute(FList[0]);
+end;
+
+function TXmlAttributes.Last: TXmlAttribute;
+begin
+ if (FList.Count = 0) then
+ Exit(nil);
+
+ Result := TXmlAttribute(FList[FList.Count - 1]);
+end;
+
+function TXmlAttributes.GetCount: integer;
+begin
+ Result := FList.Count;
+end;
+
+function TXmlAttributes.GetByIndex(const aIndex: integer): TXmlAttribute;
+begin
+ Result := TXmlAttribute(FList[aIndex]);
+end;
+
+function TXmlAttributes.GetByName(const aName: string): TXmlAttribute;
+begin
+ Result := Find(aName);
+end;
+
+procedure TXmlAttributes.SetByIndex(const aIndex: integer; const aValue: TXmlAttribute);
+begin
+ TXmlAttribute(FList[aIndex]).Assign(aValue);
+end;
+
+procedure TXmlAttributes.SetByName(const aName: string; const aValue: TXmlAttribute);
+var
+ attr: TXmlAttribute;
+begin
+ attr := Find(aName);
+ if (attr = nil) then
+ raise EAttributeNotFound.CreateFmt(SAttributeNotFound, [aName]);
+ attr.Assign(aValue);
+end;
+
+{ TXmlNode }
+
+constructor TXmlNode.Create(aOwner: TXmlNodes);
+begin
+ FOwner := aOwner;
+
+ FAttributes := TXmlAttributes.Create(Self);
+ FNodes := TXmlNodes.Create(Self);
+end;
+
+destructor TXmlNode.Destroy;
+begin
+ FNodes.Free;
+ FAttributes.Free;
+ inherited;
+end;
+
+procedure TXmlNode.Assign(aSource: TPersistent);
+begin
+ if (aSource is TXmlNode) then
+ begin
+ name := TXmlNode(aSource).name;
+ Text := TXmlNode(aSource).Text;
+ Attributes.Assign(TXmlNode(aSource).Attributes);
+ Nodes.Assign(TXmlNode(aSource).Nodes);
+ end;
+end;
+
+procedure TXmlNode.SetAttributes(const aValue: TXmlAttributes);
+begin
+ FAttributes.Assign(aValue);
+end;
+
+procedure TXmlNode.SetName(const aValue: string);
+begin
+ if (FName = aValue) then
+ Exit;
+ FName := aValue;
+end;
+
+procedure TXmlNode.SetNodes(const aValue: TXmlNodes);
+begin
+ FNodes.Assign(aValue);
+end;
+
+procedure TXmlNode.SetText(const aValue: string);
+begin
+ if (FText = aValue) then
+ Exit;
+ FText := aValue;
+end;
+
+{ TXmlNodes }
+
+constructor TXmlNodes.Create(aOwner: TXmlNode);
+begin
+ FOwner := aOwner;
+
+ FList := TList.Create;
+end;
+
+destructor TXmlNodes.Destroy;
+begin
+ Clear;
+ FList.Free;
+ inherited;
+end;
+
+procedure TXmlNodes.Assign(aSource: TPersistent);
+var
+ i: integer;
+begin
+ if (aSource is TXmlNodes) then
+ begin
+ Self.Clear;
+ for i := 0 to TXmlNodes(aSource).Count - 1 do
+ Self.Add.Assign(TXmlNodes(aSource).Items[i]);
+ end;
+end;
+
+function TXmlNodes.Add: TXmlNode;
+begin
+ Result := TXmlNode.Create(Self);
+ FList.Add(Result);
+end;
+
+function TXmlNodes.Add(const aName: string; aText: string): TXmlNode;
+begin
+ Result := Insert(aName, aText, FList.Count);
+end;
+
+function TXmlNodes.Insert(const aName, aText: string; const aIndex: integer): TXmlNode;
+begin
+ Result := TXmlNode.Create(Self);
+ Result.name := aName;
+ Result.Text := aText;
+ FList.Insert(aIndex, Result);
+end;
+
+procedure TXmlNodes.Delete(const aName: string);
+var
+ i: integer;
+begin
+ i := IndexOf(aName);
+ if (i = - 1) then
+ raise ENodeNotFound.CreateFmt(SNodeNotFound, [aName]);
+
+ TXmlNode(FList[i]).Free;
+ FList.Delete(i);
+end;
+
+procedure TXmlNodes.Delete(const aIndex: integer);
+begin
+ TXmlNode(FList[aIndex]).Free;
+ FList.Delete(aIndex);
+end;
+
+procedure TXmlNodes.Clear;
+var
+ i: integer;
+begin
+ for i := FList.Count - 1 downto 0 do
+ begin
+ TXmlNode(FList[i]).Free;
+ FList.Delete(i);
+ end;
+end;
+
+procedure TXmlNodes.Exchange(const aIndexA, aIndexB: integer);
+begin
+ FList.Exchange(aIndexA, aIndexB);
+end;
+
+procedure TXmlNodes.Move(const aFromIdx, aToIdx: integer);
+begin
+ FList.Move(aFromIdx, aToIdx);
+end;
+
+function TXmlNodes.Find(const aName: string): TXmlNode;
+var
+ i: integer;
+begin
+ Result := nil;
+
+ for i := 0 to FList.Count - 1 do
+ if (SameText(TXmlNode(FList[i]).name, aName)) then
+ Exit(TXmlNode(FList[i]));
+end;
+
+function TXmlNodes.IndexOf(const aName: string): integer;
+var
+ i: integer;
+begin
+ Result := - 1;
+
+ for i := 0 to FList.Count - 1 do
+ if (SameText(TXmlNode(FList[i]).name, aName)) then
+ Exit(i);
+end;
+
+function TXmlNodes.IndexOf(aNode: TXmlNode): integer;
+var
+ i: integer;
+begin
+ Result := - 1;
+
+ for i := 0 to FList.Count - 1 do
+ if (TXmlNode(FList[i]) = aNode) then
+ Exit(i);
+end;
+
+function TXmlNodes.NodeExists(const aName: string): boolean;
+begin
+ Result := (IndexOf(aName) <> - 1);
+end;
+
+function TXmlNodes.First: TXmlNode;
+begin
+ if (FList.Count = 0) then
+ Exit(nil);
+
+ Result := TXmlNode(FList[0]);
+end;
+
+function TXmlNodes.Last: TXmlNode;
+begin
+ if (FList.Count = 0) then
+ Exit(nil);
+
+ Result := TXmlNode(FList[FList.Count - 1]);
+end;
+
+function TXmlNodes.GetCount: integer;
+begin
+ Result := FList.Count;
+end;
+
+function TXmlNodes.GetByIndex(const aIndex: integer): TXmlNode;
+begin
+ Result := TXmlNode(FList[aIndex]);
+end;
+
+function TXmlNodes.GetByName(const aName: string): TXmlNode;
+begin
+ Result := Find(aName);
+end;
+
+procedure TXmlNodes.SetByIndex(const aIndex: integer; const aValue: TXmlNode);
+begin
+ TXmlNode(FList[aIndex]).Assign(aValue);
+end;
+
+procedure TXmlNodes.SetByName(const aName: string; const aValue: TXmlNode);
+var
+ node: TXmlNode;
+begin
+ node := Find(aName);
+ if (node = nil) then
+ raise ENodeNotFound.CreateFmt(SNodeNotFound, [aName]);
+ node.Assign(aValue);
+end;
+
+{ TXmlHeader }
+
+constructor TXmlHeader.Create;
+begin
+ FAttributes := TXmlAttributes.Create(nil);
+end;
+
+destructor TXmlHeader.Destroy;
+begin
+ FAttributes.Free;
+ inherited;
+end;
+
+procedure TXmlHeader.Assign(aSource: TPersistent);
+begin
+ if (aSource is TXmlHeader) then
+ begin
+ Attributes.Assign(TXmlHeader(aSource).Attributes);
+ end;
+end;
+
+procedure TXmlHeader.SetAttributes(const aValue: TXmlAttributes);
+begin
+ FAttributes.Assign(aValue);
+end;
+
+{ TXml }
+
+constructor TXml.Create;
+begin
+ FHeader := TXmlHeader.Create;
+ FRoot := TXmlNode.Create(nil);
+ FIndentString := #9;
+end;
+
+destructor TXml.Destroy;
+begin
+ FRoot.Free;
+ FHeader.Free;
+ inherited;
+end;
+
+procedure TXml.Assign(aSource: TPersistent);
+begin
+ if (aSource is TXml) then
+ begin
+ Header.Assign(TXml(aSource).Header);
+ Root.Assign(TXml(aSource).Root);
+ IndentString := TXml(aSource).IndentString;
+ end;
+end;
+
+procedure TXml.Clear;
+begin
+ Root.Nodes.Clear;
+ Root.Attributes.Clear;
+ Root.name := '';
+ Root.Text := '';
+end;
+
+procedure TXml.Malformed(const aLine: integer);
+begin
+ Clear;
+ raise EMalformedXml.CreateFmt(SMalformedXml, [aLine]);
+end;
+
+procedure TXml.Parse(aReader: TStreamReader);
+var
+ lineIdx: integer;
+
+ procedure ParseAttributes(const aText: string; aAttributes: TXmlAttributes);
+ var
+ tokens: TArray;
+ token : string;
+ key : string;
+ Value : string;
+ begin
+ // Split into an array of attribute="value" tokens.
+ tokens := TextSplit(aText, CSpace, CDoubleQuote, [soCSSep, soCSQot, soQuoted]);
+ for token in tokens do
+ begin
+ // Skip Node name.
+ if (TextPos(token, CEquals, True) = 0) then
+ Continue;
+
+ key := Trim(TextFetchLeft(token, CEquals, True));
+ Value := Trim(TextFetchRight(token, CEquals, True));
+ if (key = EmptyStr) then
+ Malformed(lineIdx);
+ if (TextEnclosed(Value, CDoubleQuote, True) = False) then
+ Malformed(lineIdx);
+ aAttributes.Add(key, TextUnquote(Value));
+ end;
+ end;
+
+var
+ lineStr : string;
+ lineElements: TArray;
+ lineElement : string;
+ tempInt : integer;
+ tempStr : string;
+ currNode : TXmlNode;
+ tempNode : TXmlNode;
+
+ headerExpected : boolean;
+ nodeTextExpected: boolean;
+ inComment : boolean;
+ inText : boolean;
+begin
+ Clear;
+ lineIdx := 0;
+ currNode := FRoot;
+
+ headerExpected := True;
+ nodeTextExpected := False;
+ inComment := False;
+ inText := False;
+
+ while (aReader.EndOfStream = False) do
+ begin
+ lineStr := Trim(aReader.ReadLine);
+ Inc(lineIdx);
+
+ // Check for multi line comment end, and remove it from lineStr.
+ if (inComment) then
+ begin
+ tempInt := TextPos(lineStr, '-->', True);
+ if (tempInt <> 0) then
+ begin
+ lineStr := TextCopy(lineStr, tempInt + 3, MaxInt);
+ inComment := False;
+ if (lineStr = CEmpty) then
+ Continue;
+ end
+ else
+ Continue;
+ end;
+
+ // If there are multiple tags/texts/comments on a lineStr, split it.
+ lineElements := TextSplitMarkup(lineStr);
+ for lineElement in lineElements do
+ begin
+ if (TextEnclosed(lineElement, '<', '>', True)) then
+ begin
+ tempStr := TextUnEnclose(lineElement, '<', '>', True);
+
+ // Check if its a header.
+ if (TextEnclosed(tempStr, '?xml', '?')) then
+ begin
+ if (headerExpected = False) then
+ Malformed(lineIdx);
+
+ if (inText) then
+ Malformed(lineIdx);
+
+ ParseAttributes(TextUnEnclose(tempStr, '?xml', '?'), FHeader.Attributes);
+ headerExpected := False;
+ end
+
+ // Check if its a comment.
+ else if (TextEnclosed(tempStr, '!--', '--')) then
+ begin
+ { Skip, we wont load comments. }
+ Continue;
+ end
+
+ // Check if its self ending tag.
+ else if (TextEnds(tempStr, '/', True)) then
+ begin
+ tempNode := currNode.Nodes.Add(TextFetchLeft(tempStr, CSpace, True), CEmpty);
+ if (tempNode.name = CEmpty) then
+ Malformed(lineIdx);
+ if (inText) then
+ Malformed(lineIdx);
+ ParseAttributes(TextUnEnclose(tempStr, '', '/', True), tempNode.Attributes);
+ end
+
+ // Closing tag
+ else if (TextBegins(tempStr, '/', True)) then
+ begin
+ if (currNode <> FRoot) then
+ currNode := currNode.Owner.Owner;
+ if (currNode = nil) then
+ Malformed(lineIdx);
+ inText := False;
+ nodeTextExpected := False;
+ end
+
+ // Should be an opening tag.
+ else
+ begin
+ if (inText) then
+ Malformed(lineIdx);
+
+ if (TextPos(tempStr, CSpace, True) <> 0) then
+ begin
+ if (currNode = FRoot) and (currNode.name = EmptyStr) then
+ begin
+ FRoot.name := TextFetchLeft(tempStr, CSpace, True);
+ if (FRoot.name = EmptyStr) then
+ Malformed(lineIdx);
+ ParseAttributes(tempStr, FRoot.Attributes);
+ end
+ else
+ begin
+ currNode := currNode.Nodes.Add(TextFetchLeft(tempStr, CSpace, True), CEmpty);
+ if (currNode.name = CEmpty) then
+ Malformed(lineIdx);
+ ParseAttributes(tempStr, currNode.Attributes);
+ end;
+ end
+ else
+ begin
+ if (currNode = FRoot) and (currNode.name = EmptyStr) then
+ begin
+ FRoot.name := tempStr;
+ if (FRoot.name = EmptyStr) then
+ Malformed(lineIdx);
+ end
+ else
+ begin
+ currNode := currNode.Nodes.Add(tempStr, CEmpty);
+ if (currNode.name = CEmpty) then
+ Malformed(lineIdx);
+ end;
+ end;
+
+ nodeTextExpected := True;
+ end;
+ end
+ else
+ begin
+ // Check for start of multi line comment.
+ if (TextBegins(lineElement, '