You've already forked lazarus-ccr
336 lines
14 KiB
ObjectPascal
336 lines
14 KiB
ObjectPascal
![]() |
{*********************************************************}
|
||
|
{* FlashFiler: Server interface unit for DLLs *}
|
||
|
{*********************************************************}
|
||
|
|
||
|
(* ***** BEGIN LICENSE BLOCK *****
|
||
|
* Version: MPL 1.1
|
||
|
*
|
||
|
* The contents of this file are subject to the Mozilla Public License Version
|
||
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
||
|
* the License. You may obtain a copy of the License at
|
||
|
* http://www.mozilla.org/MPL/
|
||
|
*
|
||
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
||
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||
|
* for the specific language governing rights and limitations under the
|
||
|
* License.
|
||
|
*
|
||
|
* The Original Code is TurboPower FlashFiler
|
||
|
*
|
||
|
* The Initial Developer of the Original Code is
|
||
|
* TurboPower Software
|
||
|
*
|
||
|
* Portions created by the Initial Developer are Copyright (C) 1996-2002
|
||
|
* the Initial Developer. All Rights Reserved.
|
||
|
*
|
||
|
* Contributor(s):
|
||
|
*
|
||
|
* ***** END LICENSE BLOCK ***** *)
|
||
|
|
||
|
{$I ffdefine.inc}
|
||
|
|
||
|
{=====================================================================
|
||
|
NOTES:
|
||
|
|
||
|
Using this unit, you will be able to write a DLL that provides two
|
||
|
special routines. These two routines used as a pair will identify what
|
||
|
FlashFiler calls a user-defined index. A user-defined index does not
|
||
|
generate its keys automatically like the normal (composite) indexes in
|
||
|
FlashFiler, and since it does not do that it cannot compare two keys
|
||
|
for their sorted order either. However, if you provide both of these
|
||
|
routines (a build key routine and a compare key routine) then
|
||
|
FlashFiler Server will be able to store your user-defined keys and
|
||
|
index records in the table for you.
|
||
|
|
||
|
The first routine is the Build Key routine. It must be of the
|
||
|
TffKeyBuildFunc type
|
||
|
|
||
|
TffKeyBuildFunc = function (Index : integer;
|
||
|
DataRec : PffByteArray;
|
||
|
var Key;
|
||
|
KeyLen : integer) : boolean;
|
||
|
|
||
|
Index is the number of the index for which the key must be generated.
|
||
|
DataRec is a pointer to the record from which you must generate the
|
||
|
key. It is assumed that you will know the record length. Key is an
|
||
|
untyped var where you must store the generated key, and KeyLen is the
|
||
|
length of the key to be generated.
|
||
|
|
||
|
The second routine is the Compare Key routine. It must be of the
|
||
|
TffKeyCompareFunc type:
|
||
|
|
||
|
TffKeyCompareFunc = function (const Key1, Key2;
|
||
|
aData : PffCompareData) : integer;
|
||
|
|
||
|
Key1 and Key2 are untyped const variables holding the keys to be
|
||
|
compared. The object of the routine is to compare the two keys and
|
||
|
return an integer value depending on the collating sequence of the
|
||
|
keys (a negative number means 'less than', zero means 'equal' and
|
||
|
a positive number means 'greater than'). aData is a pointer to a
|
||
|
special record holding information about the comparison to be done.
|
||
|
|
||
|
PffCompareData = ^TffCompareData;
|
||
|
TffCompareData = packed record
|
||
|
cdKeyLen : longint;
|
||
|
cdDict : pointer;
|
||
|
cdIndex : longint;
|
||
|
cdFldCnt : longint;
|
||
|
cdPartLen : longint;
|
||
|
cdAscend : boolean;
|
||
|
cdNoCase : boolean;
|
||
|
end;
|
||
|
|
||
|
The cdKeyLen field is the length of the key in bytes. cdDict is a
|
||
|
field for internal purposes: it is not guaranteed to point to anything
|
||
|
when your routine gets called. cdIndex is the number of the index
|
||
|
where the keys reside. cdFldCnt will either be 0 or 1: 0 means that
|
||
|
the routine must perform a 'partial' comparison and cdPartLen is the
|
||
|
number of bytes to compare of the two keys. If cdFldCnt is 1, the
|
||
|
comparison you make must be done over the whole of the keys. cdAscend
|
||
|
determines whether the index is in ascending order or not, and hence
|
||
|
affects the result that you return. If cdAscend is true then you must
|
||
|
return a value <0 if Key1 is less than Key2, 0 if they are equal and
|
||
|
>0 otherwise. If it is false you must reverse the sign of the result
|
||
|
(ie, return <0 if Key1 > Key2, 0 if equal, >0 otherwise. cdNoCase
|
||
|
defines whether case-insensitivity is an issue with the compare: if
|
||
|
true the keys must be compared in a case-insensitive manner, if false
|
||
|
in a case-sensitive manner. Obviously cdNoCase only has meaning for
|
||
|
character or string fields.
|
||
|
|
||
|
In 16-bit Delphi the routines you write will have to be exported from
|
||
|
the DLL and must therefore (a) be marked with the export keyword and
|
||
|
(b) be explicitly exported via the exports clause.
|
||
|
|
||
|
In 32-bit Delphi the routines you write must be marked with the
|
||
|
stdcall directive. The fastcall type (and others) is not available.
|
||
|
|
||
|
Once you have created the DLL, exporting these two routines, you can
|
||
|
then configure the server (via the configuration dialog) to go and use
|
||
|
this DLL whenever it needs to index records belonging to a particular
|
||
|
database alias, table and index.
|
||
|
|
||
|
=====================================================================}
|
||
|
|
||
|
|
||
|
unit ffsrintf;
|
||
|
|
||
|
interface
|
||
|
|
||
|
uses
|
||
|
Windows,
|
||
|
SysUtils,
|
||
|
Classes,
|
||
|
ffconst,
|
||
|
ffllbase;
|
||
|
|
||
|
type
|
||
|
PffCompareData = ^TffCompareData;
|
||
|
TffCompareData = packed record {Data for comparison operations}
|
||
|
cdKeyLen : longint; {..max length of key to compare}
|
||
|
cdDict : pointer; {..dictionary (to be typecast)}
|
||
|
cdIndex : longint; {..index number}
|
||
|
cdFldCnt : longint; {..field count (partial searches)}
|
||
|
cdPartLen : longint; {..partial length (partial searches)}
|
||
|
cdAscend : boolean; {..true if keys are to be compared in ascending order}
|
||
|
cdNoCase : boolean; {..true if keys are to be case-insensitive compared}
|
||
|
end;
|
||
|
|
||
|
type
|
||
|
TffKeyCompareFunc = function (const Key1, Key2; aData : PffCompareData) : integer
|
||
|
stdcall;
|
||
|
{-Type of the key comparison routine for building an index.
|
||
|
Returns negative value if Key1 < Key2, 0 if equal, positive
|
||
|
value otherwise, aData defines the comparison criteria}
|
||
|
|
||
|
TffKeyBuildFunc = function (Index : integer;
|
||
|
DataRec : PffByteArray;
|
||
|
var Key;
|
||
|
KeyLen : integer) : boolean
|
||
|
stdcall;
|
||
|
{-Type of the generation routine for generating a key.
|
||
|
Returns true if a key was generated. KeyLen defines the number
|
||
|
of bytes required in the generated key}
|
||
|
|
||
|
|
||
|
{---Useful Key Comparison routines---}
|
||
|
function FFKeyCompareLongint(const Key1, Key2; aData : PffCompareData) : integer;
|
||
|
stdcall;
|
||
|
{-Treat Key1 and Key2 as longints, compare}
|
||
|
function FFKeyCompareBytes(const Key1, Key2; aData : PffCompareData) : integer;
|
||
|
stdcall;
|
||
|
{-Treat Key1 and Key2 as array of bytes, compare}
|
||
|
function FFKeyCompareStr(const Key1, Key2; aData : PffCompareData) : integer;
|
||
|
stdcall;
|
||
|
{-Treat Key1 and Key2 as short strings, compare}
|
||
|
function FFKeyCompareStrZ(const Key1, Key2; aData : PffCompareData) : integer;
|
||
|
stdcall;
|
||
|
{-Treat Key1 and Key2 as null-terminated strings, compare}
|
||
|
function FFKeyCompareAnsiStr(const Key1, Key2; aData : PffCompareData) : integer;
|
||
|
stdcall;
|
||
|
{-Treat Key1 and Key2 as ANSI short strings, compare}
|
||
|
function FFKeyCompareAnsiStrZ(const Key1, Key2; aData : PffCompareData) : integer;
|
||
|
stdcall;
|
||
|
{-Treat Key1 and Key2 as ANSI null-terminated strings, compare}
|
||
|
function FFKeyCompareWideChar(const Key1, Key2; aData : PffCompareData) : integer; stdcall;
|
||
|
{-Treat Key1 and Key2 as wide UNICODE characters, compare}
|
||
|
function FFKeyCompareWideStr(const Key1, Key2; aData : PffCompareData) : integer; stdcall;
|
||
|
{-Treat Key1 and Key2 as wide UNICODE null-terminated strings, compare}
|
||
|
|
||
|
function FFKeyCompareDWord(const Key1, Key2;
|
||
|
aData : PffCompareData) : integer;
|
||
|
stdcall;
|
||
|
{-Treat Key1 and Key2 as DWord, compare}
|
||
|
|
||
|
function FFKeyCompareI64(const Key1, Key2;
|
||
|
aData : PffCompareData) : integer; stdcall;
|
||
|
{-Treat Key1 and Key2 as TffInt64, compare}
|
||
|
implementation
|
||
|
|
||
|
{===Key Comparison routines==========================================}
|
||
|
function FFKeyCompareDWord(const Key1, Key2;
|
||
|
aData : PffCompareData) : integer;
|
||
|
begin
|
||
|
Result := FFCheckDescend(aData^.cdAscend, FFCmpDW(DWord(Key1),
|
||
|
DWord(Key2)));
|
||
|
end;
|
||
|
{--------}
|
||
|
function FFKeyCompareI64(const Key1, Key2;
|
||
|
aData : PffCompareData) : integer;
|
||
|
begin
|
||
|
Result := FFCheckDescend(aData^.cdAscend, FFCmpI64(TffInt64(Key1),
|
||
|
TffInt64(Key2)));
|
||
|
end;
|
||
|
{--------}
|
||
|
function FFKeyCompareLongint(const Key1, Key2; aData : PffCompareData) : integer;
|
||
|
begin
|
||
|
Result := FFCheckDescend(aData^.cdAscend, FFCmpI32(longint(Key1), longint(Key2)));
|
||
|
end;
|
||
|
{--------}
|
||
|
function FFKeyCompareBytes(const Key1, Key2; aData : PffCompareData) : integer;
|
||
|
begin
|
||
|
with aData^ do
|
||
|
Result := FFCheckDescend(cdAscend,
|
||
|
FFCmpBytes(@Key1, @Key2, FFForceNonZero(cdPartLen, cdKeyLen)));
|
||
|
end;
|
||
|
{--------}
|
||
|
function FFKeyCompareStr(const Key1, Key2; aData : PffCompareData) : integer;
|
||
|
var
|
||
|
S1 : TffShStr absolute Key1;
|
||
|
S2 : TffShStr absolute Key2;
|
||
|
begin
|
||
|
with aData^ do
|
||
|
if cdNoCase then
|
||
|
Result := FFCheckDescend(cdAscend, FFCmpShStrUC(S1, S2, FFForceNonZero(cdPartLen, cdKeyLen)))
|
||
|
else
|
||
|
Result := FFCheckDescend(cdAscend, FFCmpShStr(S1, S2, FFForceNonZero(cdPartLen, cdKeyLen)));
|
||
|
end;
|
||
|
{--------}
|
||
|
function FFKeyCompareStrZ(const Key1, Key2; aData : PffCompareData) : integer;
|
||
|
var
|
||
|
S1 : array [0..pred(ffcl_MaxKeyLength)] of AnsiChar absolute Key1;
|
||
|
S2 : array [0..pred(ffcl_MaxKeyLength)] of AnsiChar absolute Key2;
|
||
|
begin
|
||
|
with aData^ do
|
||
|
if cdNoCase then
|
||
|
Result := FFCheckDescend(cdAscend,
|
||
|
SysUtils.StrLIComp(S1, S2, FFForceNonZero(cdPartLen, cdKeyLen)))
|
||
|
else
|
||
|
Result := FFCheckDescend(cdAscend,
|
||
|
SysUtils.StrLComp(S1, S2, FFForceNonZero(cdPartLen, cdKeyLen)));
|
||
|
end;
|
||
|
{--------}
|
||
|
function FFKeyCompareAnsiStr(const Key1, Key2; aData : PffCompareData) : integer;
|
||
|
var
|
||
|
S1 : string[255] absolute Key1;
|
||
|
S2 : string[255] absolute Key2;
|
||
|
begin
|
||
|
with aData^ do
|
||
|
if cdNoCase then
|
||
|
Result := FFCheckDescend(cdAscend,
|
||
|
Windows.CompareStringA(LOCALE_USER_DEFAULT,
|
||
|
NORM_IGNORECASE,
|
||
|
PAnsiChar(@S1[1]),
|
||
|
FFMinI(FFForceNonZero(cdPartLen, cdKeyLen), length(S1)),
|
||
|
PAnsiChar(@S2[1]),
|
||
|
FFMinI(FFForceNonZero(cdPartLen, cdKeyLen), length(S2))) - 2)
|
||
|
else
|
||
|
Result := FFCheckDescend(cdAscend,
|
||
|
Windows.CompareStringA(LOCALE_USER_DEFAULT, 0,
|
||
|
PAnsiChar(@S1[1]),
|
||
|
FFMinI(FFForceNonZero(cdPartLen, cdKeyLen), length(S1)),
|
||
|
PAnsiChar(@S2[1]),
|
||
|
FFMinI(FFForceNonZero(cdPartLen, cdKeyLen), length(S2))) - 2);
|
||
|
end;
|
||
|
{--------}
|
||
|
function FFKeyCompareAnsiStrZ(const Key1, Key2; aData : PffCompareData) : integer;
|
||
|
var
|
||
|
S1 : array [0..pred(ffcl_MaxKeyLength)] of AnsiChar absolute Key1;
|
||
|
S2 : array [0..pred(ffcl_MaxKeyLength)] of AnsiChar absolute Key2;
|
||
|
begin
|
||
|
with aData^ do
|
||
|
if cdNoCase then
|
||
|
Result := FFCheckDescend(cdAscend,
|
||
|
Windows.CompareStringA(LOCALE_USER_DEFAULT,
|
||
|
NORM_IGNORECASE,
|
||
|
PAnsiChar(@S1[0]),
|
||
|
FFMinI(FFForceNonZero(cdPartLen, cdKeyLen), StrLen(S1)),
|
||
|
PAnsiChar(@S2[0]),
|
||
|
FFMinI(FFForceNonZero(cdPartLen, cdKeyLen), StrLen(S2))) - 2)
|
||
|
else
|
||
|
Result := FFCheckDescend(cdAscend,
|
||
|
Windows.CompareStringA(LOCALE_USER_DEFAULT, 0,
|
||
|
PAnsiChar(@S1[0]),
|
||
|
FFMinI(FFForceNonZero(cdPartLen, cdKeyLen), StrLen(S1)),
|
||
|
PAnsiChar(@S2[0]),
|
||
|
FFMinI(FFForceNonZero(cdPartLen, cdKeyLen), StrLen(S2))) - 2);
|
||
|
end;
|
||
|
{--------}
|
||
|
function FFKeyCompareWideChar(const Key1, Key2; aData : PffCompareData) : integer;
|
||
|
var
|
||
|
S1 : WideChar absolute Key1;
|
||
|
S2 : WideChar absolute Key2;
|
||
|
begin
|
||
|
if aData^.cdNoCase then
|
||
|
Result := FFCheckDescend(aData^.cdAscend,
|
||
|
Windows.CompareStringW
|
||
|
(LOCALE_USER_DEFAULT,
|
||
|
NORM_IGNORECASE + SORT_STRINGSORT,
|
||
|
PWideChar(@S1), 1,
|
||
|
PWideChar(@S2), 1) - 2)
|
||
|
else
|
||
|
Result := FFCheckDescend(aData^.cdAscend,
|
||
|
Windows.CompareStringW
|
||
|
(LOCALE_USER_DEFAULT, SORT_STRINGSORT,
|
||
|
PWideChar(@S1), 1,
|
||
|
PWideChar(@S2), 1) - 2);
|
||
|
end;
|
||
|
{--------}
|
||
|
function FFKeyCompareWideStr(const Key1, Key2; aData : PffCompareData) : integer;
|
||
|
var
|
||
|
S1 : array [0..pred(ffcl_MaxKeyLength div 2)] of WideChar absolute Key1;
|
||
|
S2 : array [0..pred(ffcl_MaxKeyLength div 2)] of WideChar absolute Key2;
|
||
|
begin
|
||
|
with aData^ do
|
||
|
if cdNoCase then
|
||
|
Result := FFCheckDescend(
|
||
|
cdAscend,
|
||
|
Windows.CompareStringW(LOCALE_USER_DEFAULT,
|
||
|
NORM_IGNORECASE + SORT_STRINGSORT,
|
||
|
PWideChar(@S1[0]),
|
||
|
FFMinI(FFForceNonZero(cdPartLen, cdKeyLen), lstrlenW(S1)),
|
||
|
PWideChar(@S2[0]),
|
||
|
FFMinI(FFForceNonZero(cdPartLen, cdKeyLen), lstrlenW(S2))) - 2)
|
||
|
else
|
||
|
Result := FFCheckDescend(
|
||
|
cdAscend,
|
||
|
Windows.CompareStringW(LOCALE_USER_DEFAULT, SORT_STRINGSORT,
|
||
|
PWideChar(@S1[0]),
|
||
|
FFMinI(FFForceNonZero(cdPartLen, cdKeyLen), lstrlenW(S1)),
|
||
|
PWideChar(@S2[0]),
|
||
|
FFMinI(FFForceNonZero(cdPartLen, cdKeyLen), lstrlenW(S2))) - 2);
|
||
|
end;
|
||
|
{====================================================================}
|
||
|
|
||
|
|
||
|
end.
|