diff --git a/contrib/mORMot/CrossPlatform/SynCrossPlatform.inc b/contrib/mORMot/CrossPlatform/SynCrossPlatform.inc
index 984cc9f..045e293 100644
--- a/contrib/mORMot/CrossPlatform/SynCrossPlatform.inc
+++ b/contrib/mORMot/CrossPlatform/SynCrossPlatform.inc
@@ -2,7 +2,7 @@
{
This file is part of Synopse mORMot framework.
- Synopse mORMot framework. Copyright (C) 2020 Arnaud Bouchez
+ Synopse mORMot framework. Copyright (C) 2022 Arnaud Bouchez
Synopse Informatique - https://synopse.info
*** BEGIN LICENSE BLOCK *****
@@ -21,7 +21,7 @@
The Initial Developer of the Original Code is Arnaud Bouchez.
- Portions created by the Initial Developer are Copyright (C) 2020
+ Portions created by the Initial Developer are Copyright (C) 2022
the Initial Developer. All Rights Reserved.
Contributor(s):
diff --git a/contrib/mORMot/CrossPlatform/SynCrossPlatformCrypto.pas b/contrib/mORMot/CrossPlatform/SynCrossPlatformCrypto.pas
index 89c03db..1f6b40e 100644
--- a/contrib/mORMot/CrossPlatform/SynCrossPlatformCrypto.pas
+++ b/contrib/mORMot/CrossPlatform/SynCrossPlatformCrypto.pas
@@ -6,7 +6,7 @@ unit SynCrossPlatformCrypto;
{
This file is part of Synopse mORMot framework.
- Synopse mORMot framework. Copyright (C) 2020 Arnaud Bouchez
+ Synopse mORMot framework. Copyright (C) 2022 Arnaud Bouchez
Synopse Informatique - https://synopse.info
*** BEGIN LICENSE BLOCK *****
@@ -25,7 +25,7 @@ unit SynCrossPlatformCrypto;
The Initial Developer of the Original Code is Arnaud Bouchez.
- Portions created by the Initial Developer are Copyright (C) 2020
+ Portions created by the Initial Developer are Copyright (C) 2022
the Initial Developer. All Rights Reserved.
Contributor(s):
diff --git a/contrib/mORMot/CrossPlatform/SynCrossPlatformJSON.pas b/contrib/mORMot/CrossPlatform/SynCrossPlatformJSON.pas
index 2570650..ea14163 100644
--- a/contrib/mORMot/CrossPlatform/SynCrossPlatformJSON.pas
+++ b/contrib/mORMot/CrossPlatform/SynCrossPlatformJSON.pas
@@ -6,7 +6,7 @@ unit SynCrossPlatformJSON;
{
This file is part of Synopse mORMot framework.
- Synopse mORMot framework. Copyright (C) 2020 Arnaud Bouchez
+ Synopse mORMot framework. Copyright (C) 2022 Arnaud Bouchez
Synopse Informatique - https://synopse.info
*** BEGIN LICENSE BLOCK *****
@@ -25,7 +25,7 @@ unit SynCrossPlatformJSON;
The Initial Developer of the Original Code is Arnaud Bouchez.
- Portions created by the Initial Developer are Copyright (C) 2020
+ Portions created by the Initial Developer are Copyright (C) 2022
the Initial Developer. All Rights Reserved.
Contributor(s):
@@ -1682,7 +1682,7 @@ begin
VKind := jvObject else
if VKind<>jvObject then
raise EJSONException.CreateFmt('AddNameValue(%s) over array',[aName]);
- if VCount<=length(Values) then begin
+ if VCount=length(Values) then begin
SetLength(Values,VCount+VCount shr 3+32);
SetLength(Names,VCount+VCount shr 3+32);
end;
@@ -1697,7 +1697,7 @@ begin
VKind := jvArray else
if VKind<>jvArray then
raise EJSONException.Create('AddValue() over object');
- if VCount<=length(Values) then
+ if VCount=length(Values) then
SetLength(Values,VCount+VCount shr 3+32);
Values[VCount] := aValue;
inc(VCount);
diff --git a/contrib/mORMot/CrossPlatform/SynCrossPlatformREST.pas b/contrib/mORMot/CrossPlatform/SynCrossPlatformREST.pas
index 5acb124..19f66f9 100644
--- a/contrib/mORMot/CrossPlatform/SynCrossPlatformREST.pas
+++ b/contrib/mORMot/CrossPlatform/SynCrossPlatformREST.pas
@@ -6,7 +6,7 @@ unit SynCrossPlatformREST;
{
This file is part of Synopse mORMot framework.
- Synopse mORMot framework. Copyright (C) 2020 Arnaud Bouchez
+ Synopse mORMot framework. Copyright (C) 2022 Arnaud Bouchez
Synopse Informatique - https://synopse.info
*** BEGIN LICENSE BLOCK *****
@@ -25,7 +25,7 @@ unit SynCrossPlatformREST;
The Initial Developer of the Original Code is Arnaud Bouchez.
- Portions created by the Initial Developer are Copyright (C) 2020
+ Portions created by the Initial Developer are Copyright (C) 2022
the Initial Developer. All Rights Reserved.
Contributor(s):
@@ -253,8 +253,8 @@ type
/// a set of published property Kind
TSQLFieldKinds = set of TSQLFieldKind;
- { TODO: TID should be a string since number is limited to 53-bit in JavaScript
- -> define and use an explicit Int52 type for SMS }
+ { Should TID be a string since number is limited to 53-bit in JavaScript?
+ -> or define and use an explicit Int52 type for SMS? }
/// the TSQLRecord primary key is a 64 bit integer
TID = {$ifndef ISDWS}type{$endif} Int64;
@@ -2895,7 +2895,7 @@ begin
end;
/// marshall {result:...,id:...} and {result:...} body answers
-function CallGetResult(const aCall: TSQLRestURIParams; var outID: integer): variant;
+function CallGetResult(const aCall: TSQLRestURIParams; var outID: TID): variant;
{$ifndef ISSMS}
var doc: TJSONVariantData;
jsonres: string;
@@ -2922,7 +2922,7 @@ end;
function TSQLRestClientURI.CallBackGetResult(const aMethodName: string;
const aNameValueParameters: array of const; aTable: TSQLRecordClass; aID: TID): string;
var Call: TSQLRestURIParams;
- dummyID: integer;
+ dummyID: TID;
begin
CallBackGet(aMethodName,aNameValueParameters,Call,aTable,aID);
result := CallGetResult(Call,dummyID);
@@ -3038,7 +3038,7 @@ begin
onError(self);
exit;
end;
- var outID: integer;
+ var outID: TID;
var result := CallGetResult(Call,outID); // from {result:...,id:...}
if VarIsValidRef(result) then begin
if (aCaller.fInstanceImplementation=sicClientDriven) and (outID<>0) then
@@ -3067,7 +3067,7 @@ function TSQLRestClientURI.CallRemoteServiceSynch(aCaller: TServiceClientAbstrac
const aInputParams: array of variant; aReturnsCustomAnswer: boolean): TVariantDynArray;
var Call: TSQLRestURIParams;
outResult: variant;
- outID: integer;
+ outID: TID;
procedure RaiseError;
begin
raise EServiceException.CreateFmt('Error calling %s.%s - returned status %d',
@@ -3119,7 +3119,8 @@ var Call: TSQLRestURIParams;
result: variant;
bodyerror: string;
arr: PJSONVariantData;
- i,outID: integer;
+ i: integer;
+ outID: TID;
begin
params.Init;
for i := 0 to high(aInputParams) do
@@ -3671,7 +3672,7 @@ end;
constructor TServiceClientAbstract.Create(aClient: TSQLRestClientURI);
var Call: TSQLRestURIParams; // manual synchronous call
- dummyID: integer;
+ dummyID: TID;
result: variant;
contract: string;
begin
diff --git a/contrib/mORMot/CrossPlatform/SynCrossPlatformSpecific.pas b/contrib/mORMot/CrossPlatform/SynCrossPlatformSpecific.pas
index 1f0d3c9..1cc4dfb 100644
--- a/contrib/mORMot/CrossPlatform/SynCrossPlatformSpecific.pas
+++ b/contrib/mORMot/CrossPlatform/SynCrossPlatformSpecific.pas
@@ -6,7 +6,7 @@ unit SynCrossPlatformSpecific;
{
This file is part of Synopse mORMot framework.
- Synopse mORMot framework. Copyright (C) 2020 Arnaud Bouchez
+ Synopse mORMot framework. Copyright (C) 2022 Arnaud Bouchez
Synopse Informatique - https://synopse.info
*** BEGIN LICENSE BLOCK *****
@@ -25,7 +25,7 @@ unit SynCrossPlatformSpecific;
The Initial Developer of the Original Code is Arnaud Bouchez.
- Portions created by the Initial Developer are Copyright (C) 2020
+ Portions created by the Initial Developer are Copyright (C) 2022
the Initial Developer. All Rights Reserved.
Contributor(s):
diff --git a/contrib/mORMot/CrossPlatform/SynCrossPlatformSynLZ.pas b/contrib/mORMot/CrossPlatform/SynCrossPlatformSynLZ.pas
index d038c6f..8a69505 100644
--- a/contrib/mORMot/CrossPlatform/SynCrossPlatformSynLZ.pas
+++ b/contrib/mORMot/CrossPlatform/SynCrossPlatformSynLZ.pas
@@ -8,7 +8,7 @@ interface
{
This file is part of Synopse mORMot framework.
- Synopse mORMot framework. Copyright (C) 2020 Arnaud Bouchez
+ Synopse mORMot framework. Copyright (C) 2022 Arnaud Bouchez
Synopse Informatique - https://synopse.info
*** BEGIN LICENSE BLOCK *****
@@ -27,7 +27,7 @@ interface
The Initial Developer of the Original Code is Arnaud Bouchez.
- Portions created by the Initial Developer are Copyright (C) 2020
+ Portions created by the Initial Developer are Copyright (C) 2022
the Initial Developer. All Rights Reserved.
Contributor(s):
@@ -86,10 +86,10 @@ type
{$ifdef FPC}
PBytes = PAnsiChar;
{$else}
- PtrUInt = {$ifdef CPUX64} NativeUInt {$else} cardinal {$endif};
+ PtrUInt = {$ifdef UNICODE} NativeUInt {$else} cardinal {$endif};
TBytes = array[0..maxInt-1] of byte;
PBytes = ^TBytes;
-{$endif}
+{$endif FPC}
function SynLZcomp(src: pointer; size: cardinal; dst: pointer): cardinal;
var dst_beg, // initial dst value
@@ -190,7 +190,7 @@ function SynLZdecomp(src: pointer; size: cardinal; dst: pointer): cardinal;
var last_hashed, // initial src and dst value
src_end: PtrUInt;
CW, CWbit: cardinal;
- v, t, h, o: cardinal;
+ v, t, h, o: PtrUInt;
i: integer;
offset: array[0..4095] of PtrUInt; // 16KB hashing code
label nextCW;
diff --git a/contrib/mORMot/CrossPlatform/SynCrossPlatformTests.pas b/contrib/mORMot/CrossPlatform/SynCrossPlatformTests.pas
index 49aec4c..b3e5eca 100644
--- a/contrib/mORMot/CrossPlatform/SynCrossPlatformTests.pas
+++ b/contrib/mORMot/CrossPlatform/SynCrossPlatformTests.pas
@@ -6,7 +6,7 @@ unit SynCrossPlatformTests;
{
This file is part of Synopse mORMot framework.
- Synopse mORMot framework. Copyright (C) 2020 Arnaud Bouchez
+ Synopse mORMot framework. Copyright (C) 2022 Arnaud Bouchez
Synopse Informatique - https://synopse.info
*** BEGIN LICENSE BLOCK *****
@@ -25,7 +25,7 @@ unit SynCrossPlatformTests;
The Initial Developer of the Original Code is Arnaud Bouchez.
- Portions created by the Initial Developer are Copyright (C) 2020
+ Portions created by the Initial Developer are Copyright (C) 2022
the Initial Developer. All Rights Reserved.
Contributor(s):
diff --git a/contrib/mORMot/PasZip.pas b/contrib/mORMot/PasZip.pas
index 5eaf4d2..0fb1ee8 100644
--- a/contrib/mORMot/PasZip.pas
+++ b/contrib/mORMot/PasZip.pas
@@ -6,7 +6,7 @@ unit PasZip;
{
This file is part of Synopse framework.
- Synopse framework. Copyright (C) 2020 Arnaud Bouchez
+ Synopse framework. Copyright (C) 2022 Arnaud Bouchez
Synopse Informatique - https://synopse.info
This library is free software; you can redistribute it and/or modify it
@@ -52,7 +52,7 @@ uses
Windows,
{$else}
Types,
-{$endif}
+{$endif MSWINDOWS}
SysUtils;
type
@@ -62,10 +62,11 @@ type
{$else}
RawByteZip = AnsiString;
TZipName = AnsiString;
-{$endif}
+{$endif HASCODEPAGE}
+
{$ifdef DELPHI5OROLDER}
PCardinal = ^cardinal;
-{$endif}
+{$endif DELPHI5OROLDER}
/// compress memory using the ZLib DEFLATE algorithm
function CompressMem(src, dst: pointer; srcLen, dstLen: integer): integer;
@@ -81,6 +82,7 @@ function UncompressString(const data: RawByteZip): RawByteZip;
{$ifdef MSWINDOWS} { use Windows MapFile }
+
function CompressFile(const srcFile, dstFile: TFileName; failIfGrow: boolean = false): boolean;
function UncompressFile(const srcFile, dstFile: TFileName;
@@ -169,7 +171,7 @@ const
$cabac28a, $53b39330, $24b4a3a6, $bad03605, $cdd70693, $54de5729, $23d967bf,
$b3667a2e, $c4614ab8, $5d681b02, $2a6f2b94, $b40bbe37, $c30c8ea1, $5a05df1b,
$2d02ef8d);
-{$endif}
+{$endif DYNAMIC_CRC_TABLE}
{$ifdef MSWINDOWS}
@@ -304,9 +306,9 @@ type
constructor Create(const aFileName: TFileName); overload;
/// compress (using the deflate method) a memory buffer, and add it to the zip file
// - by default, the 1st of January, 2010 is used if not date is supplied
- procedure AddDeflated(const aZipName: TZipName; Buf: pointer; Size:
- integer; CompressLevel: integer = 6; FileAge: integer = 1 + 1 shl 5 + 30
- shl 9); overload;
+ procedure AddDeflated(const aZipName: TZipName;
+ Buf: pointer; Size: integer; CompressLevel: integer = 6;
+ FileAge: integer = 1 + 1 shl 5 + 30 shl 9); overload;
/// compress (using the deflate method) a file, and add it to the zip file
procedure AddDeflated(const aFileName: TFileName; RemovePath: boolean = true;
CompressLevel: integer = 6); overload;
@@ -345,10 +347,10 @@ begin // should be fast enough in practice, especially inlined
repeat
Dst^ := PByteArray(Src)[PtrUInt(Dst)];
inc(Dst);
- until PtrUInt(Dst)=Count;
+ until PtrUInt(Dst) = Count;
end;
{$else}
-procedure MoveWithOverlap(Src: PByte; Dst: PByte; Count: Integer);
+procedure MoveWithOverlap(Src: PByte; Dst: PByte; Count: integer);
{$ifdef FPC} nostackframe; assembler; {$endif}
asm // eax=source edx=dest ecx=count
push edx
@@ -370,7 +372,7 @@ asm // eax=source edx=dest ecx=count
pop edi
@exit:
end;
-{$endif}
+{$endif PUREPASCAL}
//----------------- general library stuff
@@ -415,20 +417,19 @@ type
);
// inflate codes private state
- PInflateCodesState = ^TInflateCodesState;
TInflateCodesState = record
Mode: TInflateCodesMode; // current inflate codes mode
// mode dependent information
Len: Cardinal;
- Sub: record // submode
+ Sub: record // submode
case Byte of
- 0:(Code: record // if Len or Distance, where in tree
+ 0:(Code: record // if Len or Distance, where in tree
Tree: PInflateHuft; // pointer into tree
- need: Cardinal; // bits needed
+ need: Cardinal; // bits needed
end);
- 1:(lit: Cardinal); // if icmLit, literal
- 2:(copy: record // if EXT or icmCopy, where and how much
- get: Cardinal; // bits to get for extra
+ 1:(lit: Cardinal); // if icmLit, literal
+ 2:(copy: record // if EXT or icmCopy, where and how much
+ get: Cardinal; // bits to get for extra
Distance: Cardinal; // distance back to copy from
end);
end;
@@ -438,8 +439,10 @@ type
LiteralTree: PInflateHuft; // literal/length/eob tree
DistanceTree: PInflateHuft; // distance tree
end;
+ PInflateCodesState = ^TInflateCodesState;
- TInflateBlockMode = (ibmZType, // get type bits (3, including end bit)
+ TInflateBlockMode = (
+ ibmZType, // get type bits (3, including end bit)
ibmLens, // get lengths for stored
ibmStored, // processing stored block
ibmTable, // get table lengths
@@ -452,27 +455,26 @@ type
);
// inflate blocks semi-private state
- PInflateBlocksState = ^TInflateBlocksState;
TInflateBlocksState = record
- Mode: TInflateBlockMode; // current inflate block mode
+ Mode: TInflateBlockMode; // current inflate block mode
// mode dependent information
- Sub: record // submode
+ Sub: record // submode
case Byte of
- 0: (left: Cardinal); // if ibmStored, bytes left to copy
- 1: (Trees: record // if DistanceTree, decoding info for trees
+ 0: (left: Cardinal); // if ibmStored, bytes left to copy
+ 1: (Trees: record // if DistanceTree, decoding info for trees
Table: Cardinal; // table lengths (14 Bits)
Index: Cardinal; // index into blens (or BitOrder)
blens: TPACardinal; // bit lengths of codes
BB: Cardinal; // bit length tree depth
TB: PInflateHuft; // bit length decoding tree
end);
- 2: (decode: record // if ibmCodes, current state
+ 2: (decode: record // if ibmCodes, current state
TL: PInflateHuft;
TD: PInflateHuft; // trees to free
codes: PInflateCodesState;
end);
end;
- Last: Boolean; // True if this block is the last block
+ Last: boolean; // True if this block is the last block
// mode independent information
bitk: Cardinal; // bits in bit buffer
bitb: Cardinal; // bit buffer
@@ -482,6 +484,7 @@ type
read: PByte; // window read pointer
write: PByte; // window write pointer
end;
+ PInflateBlocksState = ^TInflateBlocksState;
// The application must update NextInput and AvailableInput when AvailableInput has dropped to zero. It must update
// NextOutput and AvailableOutput when AvailableOutput has dropped to zero. All other fields are set by the
@@ -540,21 +543,21 @@ type
fc: record
case Byte of
0:
- (Frequency: Word); // frequency count
+ (Frequency: word); // frequency count
1:
- (Code: Word); // bit string
+ (Code: word); // bit string
end;
dl: record
case Byte of
0:
- (dad: Word); // father node in Huffman tree
+ (dad: word); // father node in Huffman tree
1:
- (Len: Word); // length of bit string
+ (Len: word); // length of bit string
end;
end;
TLiteralTree = array[0..HEAP_SIZE - 1] of TTreeEntry; // literal and length tree
- TDistanceTree = array[0..2 * D_CODES] of TTreeEntry; // distance tree
- THuffmanTree = array[0..2 * BL_CODES] of TTreeEntry; // Huffman tree for bit lengths
+ TDistanceTree = array[0..2 * D_CODES] of TTreeEntry; // distance tree
+ THuffmanTree = array[0..2 * BL_CODES] of TTreeEntry; // Huffman tree for bit lengths
PTree = ^TTree;
TTree = array[0..(MaxInt div SizeOf(TTreeEntry)) - 1] of TTreeEntry; // generic tree type
@@ -562,15 +565,15 @@ type
TStaticTreeDescriptor = record
StaticTree: PTree; // static tree or nil
ExtraBits: TPAInteger; // extra bits for each code or nil
- ExtraBase: Integer; // base index for ExtraBits
- Elements: Integer; // max number of elements in the tree
- MaxLength: Integer; // max bit length for the codes
+ ExtraBase: integer; // base index for ExtraBits
+ Elements: integer; // max number of elements in the tree
+ MaxLength: integer; // max bit length for the codes
end;
PTreeDescriptor = ^TTreeDescriptor;
TTreeDescriptor = record
DynamicTree: PTree;
- MaxCode: Integer; // largest code with non zero frequency
+ MaxCode: integer; // largest code with non zero frequency
StaticDescriptor: PStaticTreeDescriptor; // the corresponding static tree
end;
@@ -578,9 +581,9 @@ type
TDeflateState = record
ZState: PZState; // pointer back to this zlib stream
PendingBuffer: TPAByte; // output still pending
- PendingBufferSize: Integer;
+ PendingBufferSize: integer;
PendingOutput: PByte; // next pending byte to output to the stream
- Pending: Integer; // nb of bytes in the pending buffer
+ Pending: integer; // nb of bytes in the pending buffer
WindowSize: Cardinal; // LZ77 window size (32K by default)
WindowBits: Cardinal; // log2(WindowSize) (8..16)
WindowMask: Cardinal; // WindowSize - 1
@@ -596,7 +599,7 @@ type
// Actual size of Window: 2 * WSize, except when the user input buffer
// is directly used as sliding window.
- CurrentWindowSize: Integer;
+ CurrentWindowSize: integer;
// Link to older string with same hash index. to limit the size of this
// array to 64K, this link is maintained only for the last 32K strings.
@@ -616,10 +619,10 @@ type
// Window position at the beginning of the current output block. Gets
// negative when the window is moved backwards.
- BlockStart: Integer;
+ BlockStart: integer;
MatchLength: Cardinal; // length of best match
PreviousMatch: Cardinal; // previous match
- MatchAvailable: Boolean; // set if previous match exists
+ MatchAvailable: boolean; // set if previous match exists
StringStart: Cardinal; // start of string to insert
MatchStart: Cardinal; // start of matching string
Lookahead: Cardinal; // number of valid bytes ahead in window
@@ -635,11 +638,11 @@ type
DistanceDescriptor: TTreeDescriptor; // Descriptor for distance tree
BitLengthDescriptor: TTreeDescriptor; // Descriptor for bit length tree
- BitLengthCounts: array[0..MAX_BITS] of Word; // number of codes at each bit length for an optimal tree
+ BitLengthCounts: array[0..MAX_BITS] of word; // number of codes at each bit length for an optimal tree
- Heap: array[0..2 * L_CODES] of Integer; // heap used to build the Huffman trees
- HeapLength: Integer; // number of elements in the heap
- HeapMaximum: Integer; // element of largest frequency
+ Heap: array[0..2 * L_CODES] of integer; // heap used to build the Huffman trees
+ HeapLength: integer; // number of elements in the heap
+ HeapMaximum: integer; // element of largest frequency
// The sons of Heap[N] are Heap[2 * N] and Heap[2 * N + 1]. Heap[0] is not used.
// The same heap array is used to build all trees.
@@ -669,13 +672,13 @@ type
// Buffer for distances. To simplify the code, DistanceBuffer and LiteralBuffer have
// the same number of elements. To use different lengths, an extra flag array would be necessary.
DistanceBuffer: TPAWord;
- OptimalLength: Integer; // bit length of current block with optimal trees
- StaticLength: Integer; // bit length of current block with static trees
- CompressedLength: Integer; // total bit length of compressed file
+ OptimalLength: integer; // bit length of current block with optimal trees
+ StaticLength: integer; // bit length of current block with static trees
+ CompressedLength: integer; // total bit length of compressed file
Matches: Cardinal; // number of string matches in current block
- LastEOBLength: Integer; // bit length of EOB code for last block
- BitsBuffer: Word; // Output buffer. Bits are inserted starting at the bottom (least significant bits).
- ValidBits: Integer; // Number of valid bits in BitsBuffer. All Bits above the last valid bit are always zero.
+ LastEOBLength: integer; // bit length of EOB code for last block
+ BitsBuffer: word; // Output buffer. Bits are inserted starting at the bottom (least significant bits).
+ ValidBits: integer; // Number of valid bits in BitsBuffer. All Bits above the last valid bit are always zero.
end;
//----------------- Huffmann trees
@@ -853,7 +856,7 @@ const
);
// first normalized distance for each code (0 = distance of 1)
- BaseDistance: array[0..D_CODES - 1] of Integer = (
+ BaseDistance: array[0..D_CODES - 1] of integer = (
0, 1, 2, 3, 4, 6, 8, 12, 16, 24,
32, 48, 64, 96, 128, 192, 256, 384, 512, 768,
1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576
@@ -867,17 +870,19 @@ const
REPZ_11_138 = 18; // repeat a zero length 11-138 times (7 Bits of repeat count)
// extra bits for each length code
- ExtraLengthBits: array[0..LENGTH_CODES - 1] of Integer = (
- 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0
+ ExtraLengthBits: array[0..LENGTH_CODES - 1] of integer = (
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3,
+ 4, 4, 4, 4, 5, 5, 5, 5, 0
);
// extra bits for each distance code
- ExtraDistanceBits: array[0..D_CODES - 1] of Integer = (
- 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10 ,10, 11, 11, 12, 12, 13, 13
+ ExtraDistanceBits: array[0..D_CODES - 1] of integer = (
+ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8,
+ 9, 9, 10 ,10, 11, 11, 12, 12, 13, 13
);
// extra bits for each bit length code
- ExtraBitLengthBits: array[0..BL_CODES - 1] of Integer = (
+ ExtraBitLengthBits: array[0..BL_CODES - 1] of integer = (
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 7
);
@@ -918,10 +923,11 @@ const
//----------------- Inflate support
const
- InflateMask: array[0..16] of Cardinal = ($0000, $0001, $0003, $0007, $000F,
- $001F, $003F, $007F, $00FF, $01FF, $03FF, $07FF, $0FFF, $1FFF, $3FFF, $7FFF, $FFFF);
+ InflateMask: array[0..16] of Cardinal = (
+ $0000, $0001, $0003, $0007, $000F, $001F, $003F, $007F,
+ $00FF, $01FF, $03FF, $07FF, $0FFF, $1FFF, $3FFF, $7FFF, $FFFF);
-function InflateFlush(var S: TInflateBlocksState; var Z: TZState; R: Integer): Integer;
+function InflateFlush(var S: TInflateBlocksState; var Z: TZState; R: integer): integer;
// copies as much as possible from the sliding window to the output area
var
N: Cardinal;
@@ -952,7 +958,8 @@ begin
Inc(Q, N);
// see if more to copy at beginning of window
- if Q = S.zend then begin
+ if Q = S.zend then
+ begin
// wrap pointers
Q := S.Window;
if S.write = S.zend then
@@ -976,11 +983,11 @@ begin
Z.NextOutput := P;
S.Read := Q;
- Result := R;
+ result := R;
end;
function InflateFast(LiteralBits, DistanceBits: Cardinal; TL, TD: PInflateHuft;
- var S: TInflateBlocksState; var Z: TZState): Integer;
+ var S: TInflateBlocksState; var Z: TZState): integer;
// Called with number of bytes left to write in window at least 258 (the maximum string length) and number of input
// bytes available at least ten. The ten bytes are six bytes for the longest length/distance pair plus four bytes for
// overloading the bit buffer.
@@ -1017,7 +1024,8 @@ begin
// assume called with (M >= 258) and (N >= 10)
repeat
// get literal/length Code
- while K < 20 do begin
+ while K < 20 do
+ begin
Dec(N);
BitsBuffer := BitsBuffer or (cardinal(P^) shl K);
Inc(K, 8);
@@ -1027,7 +1035,8 @@ begin
Temp := @PHuftField(TL)[BitsBuffer and ml];
Extra := Temp.exop;
- if Extra = 0 then begin
+ if Extra = 0 then
+ begin
BitsBuffer := BitsBuffer shr Temp.Bits;
Dec(K, Temp.Bits);
Q^ := Temp.Base;
@@ -1043,14 +1052,16 @@ begin
BitsBuffer := BitsBuffer shr Temp.Bits;
Dec(K, Temp.Bits);
- if (Extra and 16) <> 0 then begin
+ if (Extra and 16) <> 0 then
+ begin
// get extra bits for length
Extra := Extra and 15;
C := Temp.Base + (BitsBuffer and InflateMask[Extra]);
BitsBuffer := BitsBuffer shr Extra;
Dec(K, Extra);
// decode distance base of block to copy
- while K < 15 do begin
+ while K < 15 do
+ begin
Dec(N);
BitsBuffer := BitsBuffer or (Cardinal(P^) shl K);
Inc(P);
@@ -1062,10 +1073,12 @@ begin
repeat
BitsBuffer := BitsBuffer shr Temp.Bits;
Dec(K, Temp.Bits);
- if (Extra and 16) <> 0 then begin
+ if (Extra and 16) <> 0 then
+ begin
// get extra bits to add to distance base
Extra := Extra and 15;
- while K < Extra do begin
+ while K < Extra do
+ begin
Dec(N);
BitsBuffer := BitsBuffer or (Cardinal(P^) shl K);
Inc(P);
@@ -1077,19 +1090,22 @@ begin
// do the copy
Dec(M, C);
// offset before Dest
- if (PtrUInt(Q) - PtrUInt(S.Window)) >= D then begin
+ if (PtrUInt(Q) - PtrUInt(S.Window)) >= D then
+ begin
// copy without extra
R := Q;
Dec(R, D);
end
- else begin
+ else
+ begin
// offset after destination,
// bytes from offset to end
Extra := D - (PtrUInt(Q) - PtrUInt(S.Window));
R := S.zend;
// pointer to offset
Dec(R, Extra);
- if C > Extra then begin
+ if C > Extra then
+ begin
// copy to end of window
Dec(C, Extra);
MoveWithOverlap(R, Q, Extra);
@@ -1104,11 +1120,13 @@ begin
inc(Q,Extra);
Break;
end
- else if (Extra and 64) = 0 then begin
+ else if (Extra and 64) = 0 then
+ begin
Inc(Temp, Temp.Base + (BitsBuffer and InflateMask[Extra]));
Extra := Temp.exop;
end
- else begin
+ else
+ begin
C := Z.AvailableInput - N;
if (K shr 3) < C then
C := K shr 3;
@@ -1121,17 +1139,19 @@ begin
Inc(Z.TotalInput, PtrUInt(P) - PtrUInt(Z.NextInput));
Z.NextInput := P;
S.write := Q;
- Result := Z_DATA_ERROR;
- Exit;
+ result := Z_DATA_ERROR;
+ exit;
end;
until False;
Break;
end;
- if (Extra and 64) = 0 then begin
+ if (Extra and 64) = 0 then
+ begin
Inc(Temp, Temp.Base + (BitsBuffer and InflateMask[Extra]));
Extra := Temp.exop;
- if Extra = 0 then begin
+ if Extra = 0 then
+ begin
BitsBuffer := BitsBuffer shr Temp.Bits;
Dec(K, Temp.Bits);
Q^ := Temp.Base;
@@ -1140,7 +1160,8 @@ begin
Break;
end;
end
- else if (Extra and 32) <> 0 then begin
+ else if (Extra and 32) <> 0 then
+ begin
C := Z.AvailableInput - N;
if (K shr 3) < C then
C := K shr 3;
@@ -1153,10 +1174,11 @@ begin
Inc(Z.TotalInput, PtrUInt(P) - PtrUInt(Z.NextInput));
Z.NextInput := P;
S.write := Q;
- Result := Z_STREAM_END;
- Exit;
+ result := Z_STREAM_END;
+ exit;
end
- else begin
+ else
+ begin
C := Z.AvailableInput - N;
if (K shr 3) < C then
C := K shr 3;
@@ -1169,8 +1191,8 @@ begin
Inc(Z.TotalInput, PtrUInt(P) - PtrUInt(Z.NextInput));
Z.NextInput := P;
S.write := Q;
- Result := Z_DATA_ERROR;
- Exit;
+ result := Z_DATA_ERROR;
+ exit;
end;
until False;
if (M < 258) or (N < 10) then
@@ -1190,21 +1212,21 @@ begin
Inc(Z.TotalInput, PtrUInt(P) - PtrUInt(Z.NextInput));
Z.NextInput := P;
S.write := Q;
- Result := Z_OK;
+ result := Z_OK;
end;
function InflateCodesNew(LiteralBits: Cardinal; DistanceBits: Cardinal; TL, TD:
PInflateHuft; var Z: TZState): PInflateCodesState;
begin
GetMem(result, SizeOf(TInflateCodesState));
- Result.Mode := icmStart;
- Result.LiteralTreeBits := LiteralBits;
- Result.DistanceTreeBits := DistanceBits;
- Result.LiteralTree := TL;
- Result.DistanceTree := TD;
+ result.Mode := icmStart;
+ result.LiteralTreeBits := LiteralBits;
+ result.DistanceTreeBits := DistanceBits;
+ result.LiteralTree := TL;
+ result.DistanceTree := TD;
end;
-function InflateCodes(var S: TInflateBlocksState; var Z: TZState; R: Integer): Integer;
+function InflateCodes(var S: TInflateBlocksState; var Z: TZState; R: integer): integer;
var
J: Cardinal; // temporary storage
Temp: PInflateHuft;
@@ -1232,11 +1254,13 @@ begin
M := PtrUInt(S.zend) - PtrUInt(Q);
// process input and output based on current state
- while True do begin
+ while True do
+ begin
case C.Mode of
icmStart:
begin
- if (M >= 258) and (N >= 10) then begin
+ if (M >= 258) and (N >= 10) then
+ begin
S.bitb := BitsBuffer;
S.bitk := K;
Z.AvailableInput := N;
@@ -1255,7 +1279,8 @@ begin
M := PtrUInt(S.read) - PtrUInt(Q) - 1
else
M := PtrUInt(S.zend) - PtrUInt(Q);
- if R <> Z_OK then begin
+ if R <> Z_OK then
+ begin
if R = Z_STREAM_END then
C.mode := icmWash
else
@@ -1270,18 +1295,20 @@ begin
icmLen: // I: get length/literal/eob next
begin
J := C.sub.Code.need;
- while K < J do begin
+ while K < J do
+ begin
if N <> 0 then
R := Z_OK
- else begin
+ else
+ begin
S.bitb := BitsBuffer;
S.bitk := K;
Z.AvailableInput := N;
Inc(Z.TotalInput, PtrUInt(P) - PtrUInt(Z.NextInput));
Z.NextInput := P;
S.write := Q;
- Result := InflateFlush(S, Z, R);
- Exit;
+ result := InflateFlush(S, Z, R);
+ exit;
end;
Dec(N);
BitsBuffer := BitsBuffer or (Cardinal(P^) shl K);
@@ -1295,26 +1322,30 @@ begin
Extra := Temp.exop;
// literal
- if Extra = 0 then begin
+ if Extra = 0 then
+ begin
C.sub.lit := Temp.Base;
C.mode := icmLit;
Continue;
end;
// length
- if (Extra and 16) <> 0 then begin
+ if (Extra and 16) <> 0 then
+ begin
C.sub.copy.get := Extra and 15;
C.Len := Temp.Base;
C.mode := icmLenNext;
Continue;
end;
// next table
- if (Extra and 64) = 0 then begin
+ if (Extra and 64) = 0 then
+ begin
C.sub.Code.need := Extra;
C.sub.Code.Tree := @PHuftField(Temp)[Temp.Base];
Continue;
end;
// end of block
- if (Extra and 32) <> 0 then begin
+ if (Extra and 32) <> 0 then
+ begin
C.mode := icmWash;
Continue;
end;
@@ -1327,24 +1358,26 @@ begin
Inc(Z.TotalInput, PtrUInt(P) - PtrUInt(Z.NextInput));
Z.NextInput := P;
S.write := Q;
- Result := InflateFlush(S, Z, R);
- Exit;
+ result := InflateFlush(S, Z, R);
+ exit;
end;
icmLenNext: // I: getting length extra (have base)
begin
J := C.sub.copy.get;
- while K < J do begin
+ while K < J do
+ begin
if N <> 0 then
R := Z_OK
- else begin
+ else
+ begin
S.bitb := BitsBuffer;
S.bitk := K;
Z.AvailableInput := N;
Inc(Z.TotalInput, PtrUInt(P) - PtrUInt(Z.NextInput));
Z.NextInput := P;
S.write := Q;
- Result := InflateFlush(S, Z, R);
- Exit;
+ result := InflateFlush(S, Z, R);
+ exit;
end;
Dec(N);
BitsBuffer := BitsBuffer or (Cardinal(P^) shl K);
@@ -1361,18 +1394,20 @@ begin
icmDistance: // I: get distance next
begin
J := C.sub.Code.need;
- while K < J do begin
+ while K < J do
+ begin
if N <> 0 then
R := Z_OK
- else begin
+ else
+ begin
S.bitb := BitsBuffer;
S.bitk := K;
Z.AvailableInput := N;
Inc(Z.TotalInput, PtrUInt(P) - PtrUInt(Z.NextInput));
Z.NextInput := P;
S.write := Q;
- Result := InflateFlush(S, Z, R);
- Exit;
+ result := InflateFlush(S, Z, R);
+ exit;
end;
Dec(N);
BitsBuffer := BitsBuffer or (PtrUInt(P^) shl K);
@@ -1385,14 +1420,16 @@ begin
Extra := Temp.exop;
// distance
- if (Extra and 16) <> 0 then begin
+ if (Extra and 16) <> 0 then
+ begin
C.sub.copy.get := Extra and 15;
C.sub.copy.Distance := Temp.Base;
C.mode := icmDistExt;
Continue;
end;
// next table
- if (Extra and 64) = 0 then begin
+ if (Extra and 64) = 0 then
+ begin
C.sub.Code.need := Extra;
C.sub.Code.Tree := @PHuftField(Temp)[Temp.Base];
Continue;
@@ -1406,24 +1443,26 @@ begin
Inc(Z.TotalInput, PtrUInt(P) - PtrUInt(Z.NextInput));
Z.NextInput := P;
S.write := Q;
- Result := InflateFlush(S, Z, R);
- Exit;
+ result := InflateFlush(S, Z, R);
+ exit;
end;
icmDistExt: // I: getting distance extra
begin
J := C.sub.copy.get;
- while K < J do begin
+ while K < J do
+ begin
if N <> 0 then
R := Z_OK
- else begin
+ else
+ begin
S.bitb := BitsBuffer;
S.bitk := K;
Z.AvailableInput := N;
Inc(Z.TotalInput, PtrUInt(P) - PtrUInt(Z.NextInput));
Z.NextInput := P;
S.write := Q;
- Result := InflateFlush(S, Z, R);
- Exit;
+ result := InflateFlush(S, Z, R);
+ exit;
end;
Dec(N);
BitsBuffer := BitsBuffer or (Cardinal(P^) shl K);
@@ -1439,21 +1478,26 @@ begin
begin
F := Q;
Dec(F, C.sub.copy.Distance);
- if (PtrUInt(Q) - PtrUInt(S.Window)) < C.sub.copy.Distance then begin
+ if (PtrUInt(Q) - PtrUInt(S.Window)) < C.sub.copy.Distance then
+ begin
F := S.zend;
Dec(F, C.sub.copy.Distance - (PtrUInt(Q) - PtrUInt(S.Window)));
end;
- while C.Len <> 0 do begin
- if M = 0 then begin
- if (Q = S.zend) and (S.read <> S.Window) then begin
+ while C.Len <> 0 do
+ begin
+ if M = 0 then
+ begin
+ if (Q = S.zend) and (S.read <> S.Window) then
+ begin
Q := S.Window;
if PtrUInt(Q) < PtrUInt(S.read) then
M := PtrUInt(S.read) - PtrUInt(Q) - 1
else
M := PtrUInt(S.zend) - PtrUInt(Q);
end;
- if M = 0 then begin
+ if M = 0 then
+ begin
S.write := Q;
R := InflateFlush(S, Z, R);
Q := S.write;
@@ -1461,22 +1505,24 @@ begin
M := PtrUInt(S.read) - PtrUInt(Q) - 1
else
M := PtrUInt(S.zend) - PtrUInt(Q);
- if (Q = S.zend) and (S.read <> S.Window) then begin
+ if (Q = S.zend) and (S.read <> S.Window) then
+ begin
Q := S.Window;
if PtrUInt(Q) < PtrUInt(S.read) then
M := PtrUInt(S.read) - PtrUInt(Q) - 1
else
M := PtrUInt(S.zend) - PtrUInt(Q);
end;
- if M = 0 then begin
+ if M = 0 then
+ begin
S.bitb := BitsBuffer;
S.bitk := K;
Z.AvailableInput := N;
Inc(Z.TotalInput, PtrUInt(P) - PtrUInt(Z.NextInput));
Z.NextInput := P;
S.write := Q;
- Result := InflateFlush(S, Z, R);
- Exit;
+ result := InflateFlush(S, Z, R);
+ exit;
end;
end;
end;
@@ -1493,15 +1539,18 @@ begin
end;
icmLit: // O: got literal, waiting for output space
begin
- if M = 0 then begin
- if (Q = S.zend) and (S.read <> S.Window) then begin
+ if M = 0 then
+ begin
+ if (Q = S.zend) and (S.read <> S.Window) then
+ begin
Q := S.Window;
if PtrUInt(Q) < PtrUInt(S.read) then
M := PtrUInt(S.read) - PtrUInt(Q) - 1
else
M := PtrUInt(S.zend) - PtrUInt(Q);
end;
- if M = 0 then begin
+ if M = 0 then
+ begin
S.write := Q;
R := InflateFlush(S, Z, R);
Q := S.write;
@@ -1509,22 +1558,24 @@ begin
M := PtrUInt(S.read) - PtrUInt(Q) - 1
else
M := PtrUInt(S.zend) - PtrUInt(Q);
- if (Q = S.zend) and (S.read <> S.Window) then begin
+ if (Q = S.zend) and (S.read <> S.Window) then
+ begin
Q := S.Window;
if PtrUInt(Q) < PtrUInt(S.read) then
M := PtrUInt(S.read) - PtrUInt(Q) - 1
else
M := PtrUInt(S.zend) - PtrUInt(Q);
end;
- if M = 0 then begin
+ if M = 0 then
+ begin
S.bitb := BitsBuffer;
S.bitk := K;
Z.AvailableInput := N;
Inc(Z.TotalInput, PtrUInt(P) - PtrUInt(Z.NextInput));
Z.NextInput := P;
S.write := Q;
- Result := InflateFlush(S, Z, R);
- Exit;
+ result := InflateFlush(S, Z, R);
+ exit;
end;
end;
end;
@@ -1537,7 +1588,8 @@ begin
icmWash: // O: got eob, possibly More output
begin
// return unused byte, if any
- if K > 7 then begin
+ if K > 7 then
+ begin
Dec(K, 8);
Inc(N);
Dec(P);
@@ -1550,15 +1602,16 @@ begin
M := PtrUInt(S.read) - PtrUInt(Q) - 1
else
M := PtrUInt(S.zend) - PtrUInt(Q);
- if S.read <> S.write then begin
+ if S.read <> S.write then
+ begin
S.bitb := BitsBuffer;
S.bitk := K;
Z.AvailableInput := N;
Inc(Z.TotalInput, PtrUInt(P) - PtrUInt(Z.NextInput));
Z.NextInput := P;
S.write := Q;
- Result := InflateFlush(S, Z, R);
- Exit;
+ result := InflateFlush(S, Z, R);
+ exit;
end;
C.mode := icmZEnd;
end;
@@ -1571,8 +1624,8 @@ begin
Inc(Z.TotalInput, PtrUInt(P) - PtrUInt(Z.NextInput));
Z.NextInput := P;
S.write := Q;
- Result := InflateFlush(S, Z, R);
- Exit;
+ result := InflateFlush(S, Z, R);
+ exit;
end;
icmBadCode: // X: got error
begin
@@ -1583,8 +1636,8 @@ begin
Inc(Z.TotalInput, PtrUInt(P) - PtrUInt(Z.NextInput));
Z.NextInput := P;
S.write := Q;
- Result := InflateFlush(S, Z, R);
- Exit;
+ result := InflateFlush(S, Z, R);
+ exit;
end;
else
begin
@@ -1595,13 +1648,11 @@ begin
Inc(Z.TotalInput, PtrUInt(P) - PtrUInt(Z.NextInput));
Z.NextInput := P;
S.write := Q;
- Result := InflateFlush(S, Z, R);
- Exit;
+ result := InflateFlush(S, Z, R);
+ exit;
end;
end;
end;
-
- Result := Z_STREAM_ERROR;
end;
type
@@ -1617,7 +1668,8 @@ const
// Tables for deflate from PKZIP'S appnote.txt
// copy lengths for literal codes 257..285 (actually lengths - 2; also see note #13 above about 258)
CopyLengths: TDeflateLengths = (3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15,
- 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0);
+ 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195,
+ 227, 258, 0, 0);
INVALID_CODE = 112;
// extra bits for literal codes 257..285
CopyLiteralExtra: TDeflateLengths = (0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
@@ -1667,7 +1719,7 @@ const
function BuildHuffmanTables(const B: TACardinal; N, S: Cardinal; const D,
Extra: TDeflateLengths; Temp: PPInflateHuft; var M: Cardinal; HP: PHuftField;
- var HN: Cardinal; var V: TDeflateWorkArea): Integer;
+ var HN: Cardinal; var V: TDeflateWorkArea): integer;
// Given a list of code lengths and a maximum table size, make a set of tables to decode that set of codes. Returns Z_OK
// on success, Z_BUF_ERROR if the given code set is incomplete (the tables are still built in this case), Z_DATA_ERROR
@@ -1690,20 +1742,20 @@ function BuildHuffmanTables(const B: TACardinal; N, S: Cardinal; const D,
var
A: Cardinal; // counter for codes of length K
F: Cardinal; // I repeats in table every F entries
- G: Integer; // maximum code Length
- H: Integer; // table Level
+ G: integer; // maximum code Length
+ H: integer; // table Level
I: Cardinal; // counter, current code
J: Cardinal; // counter
- K: Integer; // number of bits in current code
- L: Integer; // bits per table (returned in M)
+ K: integer; // number of bits in current code
+ L: integer; // bits per table (returned in M)
Mask: Cardinal; // (1 shl W) - 1, to avoid cc - O bug on HP
P: TPCardinal; // pointer into C[], B[], or V[]
Q: PInflateHuft; // points to current table
R: TInflateHuft; // table entry for structure assignment
XP: TPCardinal; // pointer into X
- Y: Integer; // number of dummy codes added
+ Y: integer; // number of dummy codes added
Z: Cardinal; // number of entries in current table
- W: Integer; // bits before this table = (L * H)
+ W: integer; // bits before this table = (L * H)
C: array[0..BMAX] of Cardinal; // bit length count table
U: array[0..BMAX - 1] of PInflateHuft; // table stack
X: array[0..BMAX] of Cardinal; // bit offsets, then code stack
@@ -1716,11 +1768,12 @@ begin
Inc(C[B[I]]);
// nil input -> all zero length codes
- if C[0] = N then begin
+ if C[0] = N then
+ begin
Temp^ := nil;
M := 0;
- Result := Z_OK;
- Exit;
+ result := Z_OK;
+ exit;
end;
// find minimum and maximum length, bound [M] by those
@@ -1743,28 +1796,32 @@ begin
// adjust last length count to fill out codes if needed
Y := 1 shl J;
- while J < I do begin
+ while J < I do
+ begin
Dec(Y, C[J]);
- if Y < 0 then begin
+ if Y < 0 then
+ begin
// bad input: more codes than bits
- Result := Z_DATA_ERROR;
- Exit;
+ result := Z_DATA_ERROR;
+ exit;
end;
Inc(J);
Y := Y shl 1;
end;
Dec(Y, C[I]);
- if Y < 0 then begin
+ if Y < 0 then
+ begin
// bad input: more codes than bits
- Result := Z_DATA_ERROR;
- Exit;
+ result := Z_DATA_ERROR;
+ exit;
end;
Inc(C[I], Y);
// generate starting offsets into the value table for each length
X[1] := 0;
J := 0;
- for I := 1 to G - 1 do begin
+ for I := 1 to G - 1 do
+ begin
inc(J, C[I]);
X[I + 1] := J;
end;
@@ -1839,8 +1896,8 @@ begin
Z := 1 shl J;
// allocate new table (note: doesn't matter for fixed)
if HN + Z > MANY then begin
- Result := Z_MEM_ERROR;
- Exit;
+ result := Z_MEM_ERROR;
+ exit;
end;
Q := @HP[HN];
@@ -1919,20 +1976,20 @@ begin
// Return Z_BUF_ERROR if we were given an incomplete table
if (Y <> 0) and (G <> 1) then
- Result := Z_BUF_ERROR
+ result := Z_BUF_ERROR
else
- Result := Z_OK;
+ result := Z_OK;
end;
function InflateTreesBits(var C: TACardinal; var BB: Cardinal; var TB:
- PInflateHuft; HP: PHuftField; var Z: TZState): Integer;
+ PInflateHuft; HP: PHuftField; var Z: TZState): integer;
// C holds 19 code lengths
// BB - bits tree desired/actual depth
// TB - bits tree result
// HP - space for trees
// Z - for messages
var
- R: Integer;
+ R: integer;
HN: Cardinal; // hufts used in space
V: TDeflateWorkArea; // work area for BuildHuffmanTables
begin
@@ -1940,12 +1997,12 @@ begin
R := BuildHuffmanTables(C, 19, 19, CopyLengths, CopyLiteralExtra, @TB, BB, HP, HN, V);
if (R = Z_BUF_ERROR) or (BB = 0) then
R := Z_DATA_ERROR;
- Result := R;
+ result := R;
end;
function InflateTreesDynamic(NL: Cardinal; ND: Cardinal; var C: TACardinal;
var LiteralBits: Cardinal; var DistanceBits: Cardinal; var TL: PInflateHuft;
- var TD: PInflateHuft; HP: PHuftField; var Z: TZState): Integer;
+ var TD: PInflateHuft; HP: PHuftField; var Z: TZState): integer;
// NL - number of literal/length codes
// ND - number of distance codes
// C - code lengths
@@ -1956,19 +2013,19 @@ function InflateTreesDynamic(NL: Cardinal; ND: Cardinal; var C: TACardinal;
// HP - space for trees
// Z - for messages
var
- R: Integer;
+ R: integer;
HN: Cardinal; // hufts used in space
V: TDeflateWorkArea; // work area for BuildHuffmanTables
begin
HN := 0;
// allocate work area
- Result := Z_OK;
+ result := Z_OK;
// build literal/length tree
R := BuildHuffmanTables(C, NL, 257, CopyLengths, CopyLiteralExtra, @TL,
LiteralBits, HP, HN, V);
if (R <> Z_OK) or (LiteralBits = 0) then begin
- Result := R;
- Exit;
+ result := R;
+ exit;
end;
// build distance tree
R := BuildHuffmanTables(TPACardinal(@C[NL])^, ND, 0, CopyOffsets, CopyExtra, @TD,
@@ -1978,7 +2035,7 @@ begin
R := Z_DATA_ERROR
else if R <> Z_MEM_ERROR then
R := Z_DATA_ERROR;
- Result := R;
+ result := R;
end;
end;
@@ -1988,7 +2045,7 @@ const
var
// build fixed tables only once -> keep them here
- FixedBuild: Boolean;
+ FixedBuild: boolean;
FixedTablesMemory: array[0..FIXEDH - 1] of TInflateHuft;
FixedLiteralBits: Cardinal;
FixedDistanceBits: Cardinal;
@@ -1996,9 +2053,9 @@ var
FixedDistanceTable: array[0..32 - 1] of TInflateHuft;
function InflateTreesFixed(var LiteralBits: Cardinal; var DistanceBits: Cardinal;
- var TL, TD: PInflateHuft; var Z: TZState): Integer;
+ var TL, TD: PInflateHuft; var Z: TZState): integer;
var
- K: Integer; // temporary variable
+ K: integer; // temporary variable
C: TDeflateWorkArea; // length list for BuildHuffmanTables
V: TDeflateWorkArea; // work area for BuildHuffmanTables
F: Cardinal; // number of hufts used in FixedTablesMemory
@@ -2030,7 +2087,7 @@ begin
DistanceBits := FixedDistanceBits;
TL := @FixedLiteralTable;
TD := @FixedDistanceTable;
- Result := Z_OK;
+ result := Z_OK;
end;
@@ -2091,7 +2148,7 @@ var
begin
GetMem(S, SizeOf(TInflateBlocksState));
if S = nil then
- Result := S
+ result := S
else
try
GetMem(S.hufts, SizeOf(TInflateHuft) * MANY);
@@ -2100,7 +2157,7 @@ begin
Inc(S.zend, W);
S.mode := ibmZType;
InflateBlockReset(S^, Z);
- Result := S;
+ result := S;
except
if Assigned(S.Window) then
FreeMem(S.Window);
@@ -2111,7 +2168,7 @@ begin
end;
end;
-function InflateBlocks(var S: TInflateBlocksState; var Z: TZState; R: Integer): Integer;
+function InflateBlocks(var S: TInflateBlocksState; var Z: TZState; R: integer): integer;
// R contains the initial return code
var
Temp: Cardinal;
@@ -2128,7 +2185,7 @@ var
I, J, C: Cardinal;
CodeState: PInflateCodesState;
- function UpdatePointers: Integer;
+ function UpdatePointers: integer;
begin
S.bitb := B;
S.bitk := K;
@@ -2136,7 +2193,7 @@ var
Inc(Z.TotalInput, PtrUInt(P) - PtrUInt(Z.NextInput));
Z.NextInput := P;
S.write := Q;
- Result := InflateFlush(S, Z, R);
+ result := InflateFlush(S, Z, R);
end;
begin
@@ -2160,8 +2217,8 @@ begin
if N <> 0 then
R := Z_OK
else begin
- Result := UpdatePointers;
- Exit;
+ result := UpdatePointers;
+ exit;
end;
Dec(N);
B := B or (Cardinal(P^) shl K);
@@ -2170,7 +2227,7 @@ begin
end;
Temp := B and 7;
- S.last := Boolean(Temp and 1);
+ S.last := boolean(Temp and 1);
case Temp shr 1 of
0: // stored
begin
@@ -2190,8 +2247,8 @@ begin
TL, TD, Z);
if S.sub.decode.codes = nil then begin
R := Z_MEM_ERROR;
- Result := UpdatePointers;
- Exit;
+ result := UpdatePointers;
+ exit;
end;
B := B shr 3;
Dec(K, 3);
@@ -2209,8 +2266,8 @@ begin
Dec(K, 3);
S.mode := ibmBlockBad;
R := Z_DATA_ERROR;
- Result := UpdatePointers;
- Exit;
+ result := UpdatePointers;
+ exit;
end;
end;
end;
@@ -2220,8 +2277,8 @@ begin
if N <> 0 then
R := Z_OK
else begin
- Result := UpdatePointers;
- Exit;
+ result := UpdatePointers;
+ exit;
end;
Dec(N);
B := B or (Cardinal(P^) shl K);
@@ -2232,8 +2289,8 @@ begin
if (((not B) shr 16) and $FFFF) <> (B and $FFFF) then begin
S.mode := ibmBlockBad;
R := Z_DATA_ERROR;
- Result := UpdatePointers;
- Exit;
+ result := UpdatePointers;
+ exit;
end;
S.sub.left := B and $FFFF;
K := 0;
@@ -2248,8 +2305,8 @@ begin
ibmStored:
begin
if N = 0 then begin
- Result := UpdatePointers;
- Exit;
+ result := UpdatePointers;
+ exit;
end;
if M = 0 then begin
@@ -2278,8 +2335,8 @@ begin
end;
if M = 0 then begin
- Result := UpdatePointers;
- Exit;
+ result := UpdatePointers;
+ exit;
end;
end;
end;
@@ -2309,8 +2366,8 @@ begin
if N <> 0 then
R := Z_OK
else begin
- Result := UpdatePointers;
- Exit;
+ result := UpdatePointers;
+ exit;
end;
Dec(N);
B := B or (Cardinal(P^) shl K);
@@ -2323,8 +2380,8 @@ begin
if ((Temp and $1F) > 29) or (((Temp shr 5) and $1F) > 29) then begin
S.mode := ibmBlockBad;
R := Z_DATA_ERROR;
- Result := UpdatePointers;
- Exit;
+ result := UpdatePointers;
+ exit;
end;
Temp := 258 + (Temp and $1F) + ((Temp shr 5) and $1F);
GetMem(S.sub.trees.blens, Temp * SizeOf(Cardinal));
@@ -2341,8 +2398,8 @@ begin
if N <> 0 then
R := Z_OK
else begin
- Result := UpdatePointers;
- Exit;
+ result := UpdatePointers;
+ exit;
end;
Dec(N);
B := B or (Cardinal(P^) shl K);
@@ -2367,8 +2424,8 @@ begin
R := Temp;
if R = Z_DATA_ERROR then
S.mode := ibmBlockBad;
- Result := UpdatePointers;
- Exit;
+ result := UpdatePointers;
+ exit;
end;
S.sub.trees.Index := 0;
S.mode := ibmDistTree;
@@ -2384,8 +2441,8 @@ begin
if N <> 0 then
R := Z_OK
else begin
- Result := UpdatePointers;
- Exit;
+ result := UpdatePointers;
+ exit;
end;
Dec(N);
B := B or (Cardinal(P^) shl K);
@@ -2419,8 +2476,8 @@ begin
if N <> 0 then
R := Z_OK
else begin
- Result := UpdatePointers;
- Exit;
+ result := UpdatePointers;
+ exit;
end;
Dec(N);
B := B or (Cardinal(P^) shl K);
@@ -2442,8 +2499,8 @@ begin
FreeMem(S.sub.trees.blens);
S.mode := ibmBlockBad;
R := Z_DATA_ERROR;
- Result := UpdatePointers;
- Exit;
+ result := UpdatePointers;
+ exit;
end;
if C = 16 then
@@ -2467,17 +2524,17 @@ begin
S.sub.trees.blens^, LiteralBits, DistanceBits, TL, TD, S.hufts, Z);
FreeMem(S.sub.trees.blens);
if Temp <> Z_OK then begin
- if Integer(Temp) = Z_DATA_ERROR then
+ if integer(Temp) = Z_DATA_ERROR then
S.mode := ibmBlockBad;
R := Temp;
- Result := UpdatePointers;
- Exit;
+ result := UpdatePointers;
+ exit;
end;
CodeState := InflateCodesNew(LiteralBits, DistanceBits, TL, TD, Z);
if CodeState = nil then begin
R := Z_MEM_ERROR;
- Result := UpdatePointers;
- Exit;
+ result := UpdatePointers;
+ exit;
end;
S.sub.decode.codes := CodeState;
S.mode := ibmCodes;
@@ -2494,8 +2551,8 @@ begin
R := InflateCodes(S, Z, R);
if R <> Z_STREAM_END then begin
- Result := InflateFlush(S, Z, R);
- Exit;
+ result := InflateFlush(S, Z, R);
+ exit;
end;
R := Z_OK;
Freemem(S.sub.decode.codes);
@@ -2521,27 +2578,27 @@ begin
R := InflateFlush(S, Z, R);
Q := S.write;
if S.read <> S.write then begin
- Result := UpdatePointers;
- Exit;
+ result := UpdatePointers;
+ exit;
end;
S.mode := ibmBlockDone;
end;
ibmBlockDone:
begin
R := Z_STREAM_END;
- Result := UpdatePointers;
- Exit;
+ result := UpdatePointers;
+ exit;
end;
ibmBlockBad:
begin
R := Z_DATA_ERROR;
- Result := UpdatePointers;
- Exit;
+ result := UpdatePointers;
+ exit;
end;
else
R := Z_STREAM_ERROR;
- Result := UpdatePointers;
- Exit;
+ result := UpdatePointers;
+ exit;
end; // case S.mode of
end;
end;
@@ -2596,7 +2653,7 @@ function CompressMem(src, dst: pointer; srcLen, dstLen: integer): integer;
if (Scan^ <> Match^) then
Break;
until (PtrUInt(Scan) >= PtrUInt(StrEnd));
- result := MAX_MATCH - Integer(PtrUInt(StrEnd) - PtrUInt(Scan));
+ result := MAX_MATCH - integer(PtrUInt(StrEnd) - PtrUInt(Scan));
end;
const
@@ -2676,9 +2733,9 @@ function CompressMem(src, dst: pointer; srcLen, dstLen: integer): integer;
until (CurrentMatch <= Limit) or (ChainLength = 0);
if BestLen <= S.Lookahead then
- Result := BestLen
+ result := BestLen
else
- Result := S.Lookahead;
+ result := S.Lookahead;
end;
procedure FillWindow(var S: TDeflateState);
@@ -2688,7 +2745,7 @@ function CompressMem(src, dst: pointer; srcLen, dstLen: integer): integer;
// On exit at least one byte has been read, or AvailableInput = 0. Reads are performed for at least two bytes (required
// for the zip translate_eol option -> not supported here).
- function ReadBuffer(ZState: PZState; Buffer: PByte; Size: Cardinal): Integer;
+ function ReadBuffer(ZState: PZState; Buffer: PByte; Size: Cardinal): integer;
// Reads a new buffer from the current input stream, updates the Adler32 and total number of bytes read. All Deflate
// input goes through this function so some applications may wish to modify it to avoid allocating a large
// ZState.NextInput buffer and copying from it (see also FlushPending).
@@ -2699,14 +2756,14 @@ function CompressMem(src, dst: pointer; srcLen, dstLen: integer): integer;
if Len > Size then
Len := Size;
if Len = 0 then begin
- Result := 0;
- Exit;
+ result := 0;
+ exit;
end;
Dec(ZState.AvailableInput, Len);
Move(ZState.NextInput^, Buffer^, Len);
Inc(ZState.NextInput, Len);
Inc(ZState.TotalInput, Len);
- Result := Len;
+ result := Len;
end;
var
@@ -2715,7 +2772,7 @@ function CompressMem(src, dst: pointer; srcLen, dstLen: integer): integer;
More: Cardinal; // amount of free space at the end of the window
begin
repeat
- More := S.CurrentWindowSize - Integer(S.Lookahead) - Integer(S.StringStart);
+ More := S.CurrentWindowSize - integer(S.Lookahead) - integer(S.StringStart);
if (More = 0) and (S.StringStart = 0) and (S.Lookahead = 0) then
More := S.WindowSize
else if More = Cardinal(-1) then begin
@@ -2729,7 +2786,7 @@ function CompressMem(src, dst: pointer; srcLen, dstLen: integer): integer;
Dec(S.MatchStart, S.WindowSize);
Dec(S.StringStart, S.WindowSize);
// we now have StringStart >= MaxDistance
- Dec(S.BlockStart, Integer(S.WindowSize));
+ Dec(S.BlockStart, integer(S.WindowSize));
// Slide the hash table (could be avoided with 32 bit values at the expense of memory usage). We slide even when
// Level = 0 to keep the hash table consistent if we switch back to Level > 0 later. (Using Level 0 permanently
@@ -2757,7 +2814,7 @@ function CompressMem(src, dst: pointer; srcLen, dstLen: integer): integer;
end;
if S.ZState.AvailableInput = 0 then
- Exit;
+ exit;
// If there was no sliding:
// StringStart <= S.WindowSize + MaxDistance - 1 and Lookahead <= MIN_LOOKAHEAD - 1 and
@@ -2785,7 +2842,7 @@ function CompressMem(src, dst: pointer; srcLen, dstLen: integer): integer;
procedure InitializeBlock(var S: TDeflateState);
var
- N: Integer;
+ N: integer;
begin
// initialize the trees
for N := 0 to L_CODES - 1 do
@@ -2801,7 +2858,7 @@ function CompressMem(src, dst: pointer; srcLen, dstLen: integer): integer;
S.LastLiteral := 0;
end;
- procedure FlushBlockOnly(var S: TDeflateState; EOF: Boolean);
+ procedure FlushBlockOnly(var S: TDeflateState; EOF: boolean);
// Flushs the current block with given end-of-file flag.
// StringStart must be set to the end of the current match.
@@ -2832,7 +2889,7 @@ function CompressMem(src, dst: pointer; srcLen, dstLen: integer): integer;
end;
function TreeFlushBlock(var S: TDeflateState; Buffer: PByte; StoredLength:
- Integer; EOF: Boolean): Integer;
+ integer; EOF: boolean): integer;
// Determines the best encoding for the current block: dynamic trees, static trees or store, and outputs the encoded
// block. Buffer contains the input block (or nil if too old), StoredLength the length of this block and EOF if this
// is the last block.
@@ -2841,37 +2898,37 @@ function CompressMem(src, dst: pointer; srcLen, dstLen: integer): integer;
procedure BuildTree(var S: TDeflateState; var Descriptor: TTreeDescriptor);
// Constructs a Huffman tree and assigns the code bit strings and lengths.
// Updates the total bit length for the current block. The field Frequency must be set for all tree elements on entry.
- // Result: the fields Len and Code are set to the optimal bit length and corresponding Code. The length OptimalLength
+ // result: the fields Len and Code are set to the optimal bit length and corresponding Code. The length OptimalLength
// is updated; StaticLength is also updated if STree is not nil. The field MaxCode is set.
- procedure GenerateCodes(Tree: PTree; MaxCode: Integer; const
- BitLengthCounts: array of Word);
+ procedure GenerateCodes(Tree: PTree; MaxCode: integer; const
+ BitLengthCounts: array of word);
// Generates the codes for a given tree and bit counts (which need not be optimal).
// The array BitLengthCounts contains the bit length statistics for the given tree and the field Len is set for all
// Tree elements. MaxCode is the largest code with non zero frequency and BitLengthCounts are the number of codes at
// each bit length.
// On exit the field code is set for all tree elements of non zero code length.
- function BitReverse(Code: Word; Len: Integer): Word;
+ function BitReverse(Code: word; Len: integer): word;
// Reverses the first Len bits of Code, using straightforward code (a faster
// imMethod would use a table)
begin
- Result := 0;
+ result := 0;
repeat
- Result := Result or (Code and 1);
+ result := result or (Code and 1);
Code := Code shr 1;
- Result := Result shl 1;
+ result := result shl 1;
Dec(Len);
until Len <= 0;
- Result := Result shr 1;
+ result := result shr 1;
end;
var
- NextCode: array[0..MAX_BITS] of Word; // next code value for each bit length
- Code: Word; // running code value
- Bits: Integer; // bit Index
- N: Integer; // code Index
- Len: Integer;
+ NextCode: array[0..MAX_BITS] of word; // next code value for each bit length
+ Code: word; // running code value
+ Bits: integer; // bit Index
+ N: integer; // code Index
+ Len: integer;
begin
Code := 0;
// The distribution counts are first used to generate the code values without bit reversal.
@@ -2889,12 +2946,12 @@ function CompressMem(src, dst: pointer; srcLen, dstLen: integer): integer;
end;
end;
- procedure RestoreHeap(var S: TDeflateState; const Tree: TTree; K: Integer);
+ procedure RestoreHeap(var S: TDeflateState; const Tree: TTree; K: integer);
// Restores the heap property by moving down tree starting at node K,
// exchanging a Node with the smallest of its two sons if necessary, stopping
// when the heap property is re-established (each father smaller than its two sons).
var
- V, J: Integer;
+ V, J: integer;
begin
V := S.Heap[K];
J := K shl 1; // left son of K
@@ -2927,21 +2984,21 @@ function CompressMem(src, dst: pointer; srcLen, dstLen: integer): integer;
TTreeDescriptor);
// Computes the optimal bit lengths for a tree and update the total bit length for the current block.
// The fields Frequency and dad are set, Heap[HeapMaximum] and above are the tree nodes sorted by increasing frequency.
- // Result: The field Len is set to the optimal bit length, the array BitLengthCounts contains the frequencies for each
+ // result: The field Len is set to the optimal bit length, the array BitLengthCounts contains the frequencies for each
// bit length. The length OptimalLength is updated. StaticLength is also updated if STree is not nil.
var
Tree: PTree;
- MaxCode: Integer;
+ MaxCode: integer;
STree: PTree;
Extra: TPAInteger;
- Base: Integer;
- MaxLength: Integer;
- H: Integer; // heap Index
- N, M: Integer; // iterate over the tree elements
- Bits: Word; // bit length
- ExtraBits: Integer;
- F: Word; // frequency
- Overflow: Integer; // number of elements with bit length too large
+ Base: integer;
+ MaxLength: integer;
+ H: integer; // heap Index
+ N, M: integer; // iterate over the tree elements
+ Bits: word; // bit length
+ ExtraBits: integer;
+ F: word; // frequency
+ Overflow: integer; // number of elements with bit length too large
begin
Tree := Descriptor.DynamicTree;
MaxCode := Descriptor.MaxCode;
@@ -2974,13 +3031,13 @@ function CompressMem(src, dst: pointer; srcLen, dstLen: integer): integer;
if N >= Base then
ExtraBits := Extra[N - Base];
F := Tree[N].fc.Frequency;
- Inc(S.OptimalLength, Integer(F) * (Bits + ExtraBits));
+ Inc(S.OptimalLength, integer(F) * (Bits + ExtraBits));
if Assigned(STree) then
- Inc(S.StaticLength, Integer(F) * (STree[N].dl.Len + ExtraBits));
+ Inc(S.StaticLength, integer(F) * (STree[N].dl.Len + ExtraBits));
end;
// This happens for example on obj2 and pic of the Calgary corpus
if Overflow = 0 then
- Exit;
+ exit;
// find the first bit length which could increase
repeat
@@ -3011,7 +3068,7 @@ function CompressMem(src, dst: pointer; srcLen, dstLen: integer): integer;
Continue;
if Tree[M].dl.Len <> Bits then begin
Inc(S.OptimalLength, (Bits - Tree[M].dl.Len) * Tree[M].fc.Frequency);
- Tree[M].dl.Len := Word(Bits);
+ Tree[M].dl.Len := word(Bits);
end;
Dec(N);
end;
@@ -3021,10 +3078,10 @@ function CompressMem(src, dst: pointer; srcLen, dstLen: integer): integer;
var
Tree: PTree;
STree: PTree;
- Elements: Integer;
- N, M: Integer; // iterate over heap elements
- MaxCode: Integer; // largest code with non zero frequency
- Node: Integer; // new node being created
+ Elements: integer;
+ N, M: integer; // iterate over heap elements
+ MaxCode: integer; // largest code with non zero frequency
+ Node: integer; // new node being created
begin
Tree := Descriptor.DynamicTree;
@@ -3100,8 +3157,8 @@ function CompressMem(src, dst: pointer; srcLen, dstLen: integer): integer;
else
S.Depth[Node] := Byte(S.Depth[M] + 1);
- Tree[M].dl.Dad := Word(Node);
- Tree[N].dl.Dad := Word(Node);
+ Tree[M].dl.Dad := word(Node);
+ Tree[N].dl.Dad := word(Node);
// and insert the new node in the heap
S.Heap[1] := Node;
Inc(Node);
@@ -3125,7 +3182,7 @@ function CompressMem(src, dst: pointer; srcLen, dstLen: integer): integer;
if S.ValidBits > 8 then begin
S.PendingBuffer[S.Pending] := Byte(S.BitsBuffer and $FF);
Inc(S.Pending);
- S.PendingBuffer[S.Pending] := Byte(Word(S.BitsBuffer) shr 8);
+ S.PendingBuffer[S.Pending] := Byte(word(S.BitsBuffer) shr 8);
Inc(S.Pending);
end
else if S.ValidBits > 0 then begin
@@ -3136,13 +3193,13 @@ function CompressMem(src, dst: pointer; srcLen, dstLen: integer): integer;
S.ValidBits := 0;
end;
- procedure SendBits(var S: TDeflateState; Value: Word; Length: Integer);
+ procedure SendBits(var S: TDeflateState; Value: word; Length: integer);
// Value contains what is to be sent
// Length is the number of bits to send
begin
// If there's not enough room in BitsBuffer use (valid) bits from BitsBuffer and
// (16 - ValidBits) bits from Value, leaving (width - (16 - ValidBits)) unused bits in Value.
- if (S.ValidBits > Integer(BufferSize) - Length) then begin
+ if (S.ValidBits > integer(BufferSize) - Length) then begin
S.BitsBuffer := S.BitsBuffer or (Value shl S.ValidBits);
S.PendingBuffer[S.Pending] := S.BitsBuffer and $FF;
Inc(S.Pending);
@@ -3157,23 +3214,23 @@ function CompressMem(src, dst: pointer; srcLen, dstLen: integer): integer;
end;
end;
- procedure SendAllTrees(var S: TDeflateState; lcodes, dcodes, blcodes: Integer);
+ procedure SendAllTrees(var S: TDeflateState; lcodes, dcodes, blcodes: integer);
// Sends the header for a block using dynamic Huffman trees: the counts, the
// lengths of the bit length codes, the literal tree and the distance tree.
// lcodes must be >= 257, dcodes >= 1 and blcodes >= 4
procedure SendTree(var S: TDeflateState; const Tree: array of TTreeEntry;
- MaxCode: Integer);
+ MaxCode: integer);
// Sends the given tree in compressed form using the codes in BitLengthTree.
// MaxCode is the tree's largest code of non zero frequency.
var
- N: Integer; // iterates over all tree elements
- PreviousLen: Integer; // last emitted length
- CurrentLen: Integer; // length of current code
- NextLen: Integer; // length of next code
- Count: Integer; // repeat count of the current code
- MaxCount: Integer; // max repeat count
- MinCount: Integer; // min repeat count
+ N: integer; // iterates over all tree elements
+ PreviousLen: integer; // last emitted length
+ CurrentLen: integer; // length of current code
+ NextLen: integer; // length of next code
+ Count: integer; // repeat count of the current code
+ MaxCount: integer; // max repeat count
+ MinCount: integer; // min repeat count
begin
PreviousLen := -1;
NextLen := Tree[0].dl.Len;
@@ -3231,7 +3288,7 @@ function CompressMem(src, dst: pointer; srcLen, dstLen: integer): integer;
end;
var
- Rank: Integer;
+ Rank: integer;
begin
SendBits(S, lcodes - 257, 5); // not +255 as stated in appnote.txt
SendBits(S, dcodes - 1, 5);
@@ -3242,22 +3299,22 @@ function CompressMem(src, dst: pointer; srcLen, dstLen: integer): integer;
SendTree(S, S.DistanceTree, dcodes - 1);
end;
- function BuildBitLengthTree(var S: TDeflateState): Integer;
+ function BuildBitLengthTree(var S: TDeflateState): integer;
// Constructs the Huffman tree for the bit lengths and returns the Index in BitLengthOrder
// of the last bit length code to send.
procedure ScanTree(var S: TDeflateState; var Tree: array of TTreeEntry;
- MaxCode: Integer);
+ MaxCode: integer);
// Scans a given tree to determine the frequencies of the codes in the bit length tree.
// MaxCode is the tree's largest code of non zero frequency.
var
- N: Integer; // iterates over all tree elements
- PreviousLen: Integer; // last emitted length
- CurrentLen: Integer; // Length of current code
- NextLen: Integer; // length of next code
- Count: Integer; // repeat count of the current xode
- MaxCount: Integer; // max repeat count
- MinCount: Integer; // min repeat count
+ N: integer; // iterates over all tree elements
+ PreviousLen: integer; // last emitted length
+ CurrentLen: integer; // Length of current code
+ NextLen: integer; // length of next code
+ Count: integer; // repeat count of the current xode
+ MaxCount: integer; // max repeat count
+ MinCount: integer; // min repeat count
begin
PreviousLen := -1;
NextLen := Tree[0].dl.Len;
@@ -3269,7 +3326,7 @@ function CompressMem(src, dst: pointer; srcLen, dstLen: integer): integer;
MaxCount := 138;
MinCount := 3;
end;
- Tree[MaxCode + 1].dl.Len := Word($FFFF); // guard
+ Tree[MaxCode + 1].dl.Len := word($FFFF); // guard
for N := 0 to MaxCode do begin
CurrentLen := NextLen;
@@ -3317,21 +3374,21 @@ function CompressMem(src, dst: pointer; srcLen, dstLen: integer): integer;
// Determine the number of bit length codes to send. The pkzip format requires that at least 4 bit length codes
// be sent. (appnote.txt says 3 but the actual value used is 4.)
- for Result := BL_CODES - 1 downto 3 do
- if S.BitLengthTree[BitLengthOrder[Result]].dl.Len <> 0 then
+ for result := BL_CODES - 1 downto 3 do
+ if S.BitLengthTree[BitLengthOrder[result]].dl.Len <> 0 then
Break;
// update OptimalLength to include the bit length tree and counts
- Inc(S.OptimalLength, 3 * (Result + 1) + 14);
+ Inc(S.OptimalLength, 3 * (result + 1) + 14);
end;
procedure TreeStroredBlock(var S: TDeflateState; Buffer: PByte;
- StoredLength: Integer; EOF: Boolean);
+ StoredLength: integer; EOF: boolean);
// sends a stored block
// Buffer contains the input data, Len the buffer length and EOF is True if this is the last block for a file.
procedure CopyBlock(var S: TDeflateState; Buffer: PByte; Len: Cardinal;
- Header: Boolean);
+ Header: boolean);
// copies a stored block, storing first the length and its one's complement if requested
// Buffer contains the input data, Len the buffer length and Header is True if the block Header must be written too.
begin
@@ -3339,13 +3396,13 @@ function CompressMem(src, dst: pointer; srcLen, dstLen: integer): integer;
S.LastEOBLength := 8; // enough lookahead for Inflate
if Header then begin
- S.PendingBuffer[S.Pending] := Byte(Word(Len) and $FF);
+ S.PendingBuffer[S.Pending] := Byte(word(Len) and $FF);
Inc(S.Pending);
- S.PendingBuffer[S.Pending] := Byte(Word(Len) shr 8);
+ S.PendingBuffer[S.Pending] := Byte(word(Len) shr 8);
Inc(S.Pending);
- S.PendingBuffer[S.Pending] := Byte(Word(not Len) and $FF);
+ S.PendingBuffer[S.Pending] := Byte(word(not Len) and $FF);
Inc(S.Pending);
- S.PendingBuffer[S.Pending] := Byte(Word(not Len) shr 8);
+ S.PendingBuffer[S.Pending] := Byte(word(not Len) shr 8);
Inc(S.Pending);
end;
@@ -3359,7 +3416,7 @@ function CompressMem(src, dst: pointer; srcLen, dstLen: integer): integer;
begin
SendBits(S, (STORED_BLOCK shl 1) + Ord(EOF), 3); // send block type
- S.CompressedLength := (S.CompressedLength + 10) and Integer(not 7);
+ S.CompressedLength := (S.CompressedLength + 10) and integer(not 7);
Inc(S.CompressedLength, (StoredLength + 4) shl 3);
// copy with header
@@ -3371,10 +3428,10 @@ function CompressMem(src, dst: pointer; srcLen, dstLen: integer): integer;
// sends the block data compressed using the given Huffman trees
var
Distance: Cardinal; // distance of matched string
- lc: Integer; // match length or unmatched char (if Distance = 0)
+ lc: integer; // match length or unmatched char (if Distance = 0)
I: Cardinal;
Code: Cardinal; // the code to send
- Extra: Integer; // number of extra bits to send
+ Extra: integer; // number of extra bits to send
begin
I := 0;
@@ -3422,8 +3479,8 @@ function CompressMem(src, dst: pointer; srcLen, dstLen: integer): integer;
end;
var
- OptimalByteLength, StaticByteLength: Integer; // OptimalLength and StaticLength in bytes
- MacBLIndex: Integer; // index of last bit length code of non zero frequency
+ OptimalByteLength, StaticByteLength: integer; // OptimalLength and StaticLength in bytes
+ MacBLIndex: integer; // index of last bit length code of non zero frequency
begin
// construct the literal and distance trees
// After this, OptimalLength and StaticLength are the total bit lengths of
@@ -3473,27 +3530,27 @@ function CompressMem(src, dst: pointer; srcLen, dstLen: integer): integer;
Inc(S.CompressedLength, 7);
end;
- Result := S.CompressedLength shr 3;
+ result := S.CompressedLength shr 3;
end;
begin
if S.BlockStart >= 0 then
TreeFlushBlock(S, @S.Window[Cardinal(S.BlockStart)],
- Integer(S.StringStart) - S.BlockStart, EOF)
+ integer(S.StringStart) - S.BlockStart, EOF)
else
- TreeFlushBlock(S, nil, Integer(S.StringStart) - S.BlockStart, EOF);
+ TreeFlushBlock(S, nil, integer(S.StringStart) - S.BlockStart, EOF);
S.BlockStart := S.StringStart;
FlushPending(S.ZState^);
end;
- function TreeTally(var S: TDeflateState; Distance: Cardinal; lc: Cardinal): Boolean;
+ function TreeTally(var S: TDeflateState; Distance: Cardinal; lc: Cardinal): boolean;
// Saves the match info and tallies the frequency counts. Returns True if the current block must be flushed.
// Distance is the distance of the matched string and lc either match length minus MIN_MATCH or the unmatch character
// (if Distance = 0).
var
- Code: Word;
+ Code: word;
begin
- S.DistanceBuffer[S.LastLiteral] := Word(Distance);
+ S.DistanceBuffer[S.LastLiteral] := word(Distance);
S.LiteralBuffer[S.LastLiteral] := Byte(lc);
Inc(S.LastLiteral);
if (Distance = 0) then begin
@@ -3512,7 +3569,7 @@ function CompressMem(src, dst: pointer; srcLen, dstLen: integer): integer;
Inc(S.DistanceTree[Code].fc.Frequency);
end;
- Result := (S.LastLiteral = S.LiteralBufferSize - 1);
+ result := (S.LastLiteral = S.LiteralBufferSize - 1);
// We avoid equality with LiteralBufferSize because stored blocks are restricted to 64K - 1 bytes.
end;
@@ -3526,7 +3583,7 @@ function CompressMem(src, dst: pointer; srcLen, dstLen: integer): integer;
and S.HashMask;
MatchHead := S.Head[S.InsertHash];
S.Previous[(Str) and S.WindowMask] := MatchHead;
- S.Head[S.InsertHash] := Word(Str);
+ S.Head[S.InsertHash] := word(Str);
end;
const
@@ -3537,7 +3594,7 @@ var
// We overlay PendingBuffer and DistanceBuffer + LiteralBuffer. This works since the average
// output size for (length, distance) codes is <= 24 Bits.
HashHead: Cardinal; // head of the hash chain
- BlockFlush: Boolean; // set if current block must be flushed
+ BlockFlush: boolean; // set if current block must be flushed
S: TDeflateState;
begin
result := 0;
@@ -3558,14 +3615,14 @@ begin
S.HashMask := S.HashSize - 1;
S.HashShift := (S.HashBits + MIN_MATCH - 1) div MIN_MATCH;
GetMem(S.Window, S.WindowSize * (2 * SizeOf(Byte)));
- GetMem(S.Previous, S.WindowSize * SizeOf(Word));
- GetMem(S.Head, S.HashSize * SizeOf(Word));
+ GetMem(S.Previous, S.WindowSize * SizeOf(word));
+ GetMem(S.Head, S.HashSize * SizeOf(word));
S.LiteralBufferSize := 1 shl (CMemLevel + 6); // 16K elements by default
- GetMem(Overlay, S.LiteralBufferSize * (SizeOf(Word) + 2));
+ GetMem(Overlay, S.LiteralBufferSize * (SizeOf(word) + 2));
S.PendingBuffer := TPAByte(Overlay);
- S.PendingBufferSize := S.LiteralBufferSize * (SizeOf(Word) + 2);
+ S.PendingBufferSize := S.LiteralBufferSize * (SizeOf(word) + 2);
S.DistanceBuffer := @Overlay[S.LiteralBufferSize shr 1];
- S.LiteralBuffer := @S.PendingBuffer[(1 + SizeOf(Word)) * S.LiteralBufferSize];
+ S.LiteralBuffer := @S.PendingBuffer[(1 + SizeOf(word)) * S.LiteralBufferSize];
S.PendingOutput := PByte(S.PendingBuffer);
S.LiteralDescriptor.DynamicTree := @S.LiteralTree;
S.LiteralDescriptor.StaticDescriptor := @StaticLiteralDescriptor;
@@ -4323,7 +4380,7 @@ begin
inc(Str1);
inc(Str2);
until false;
- Result := ord(C1) - ord(C2);
+ result := ord(C1) - ord(C2);
end
else
result := 1 // Str2=''
@@ -4366,20 +4423,20 @@ end;
{$ifdef DELPHI5OROLDER}
function DirectoryExists(const Directory: string): boolean;
var
- Code: Integer;
+ Code: integer;
begin
Code := GetFileAttributes(pointer(Directory));
result := (Code <> -1) and (FILE_ATTRIBUTE_DIRECTORY and Code <> 0);
end;
{$endif}
-function ForceDirectories(const Dir: TFileName): Boolean;
+function ForceDirectories(const Dir: TFileName): boolean;
begin
if (Length(Dir) < 3) or DirectoryExists(Dir) or (ExtractFileDir(Dir) = Dir)
then // avoid 'x:\' problem.
- Result := true
+ result := true
else
- Result := ForceDirectories(ExtractFileDir(Dir)) and CreateDir(Dir);
+ result := ForceDirectories(ExtractFileDir(Dir)) and CreateDir(Dir);
end;
function TZipRead.CheckFile(aIndex: integer; DestPath: TFileName): boolean;
@@ -4678,7 +4735,7 @@ end;
initialization
{$ifdef DYNAMIC_CRC_TABLE}
InitCrc32Tab;
-{$endif}
+{$endif DYNAMIC_CRC_TABLE}
end.
diff --git a/contrib/mORMot/SQLite3/DDD/dom/dddDomAuthInterfaces.pas b/contrib/mORMot/SQLite3/DDD/dom/dddDomAuthInterfaces.pas
index 0f10edc..e64fe5b 100644
--- a/contrib/mORMot/SQLite3/DDD/dom/dddDomAuthInterfaces.pas
+++ b/contrib/mORMot/SQLite3/DDD/dom/dddDomAuthInterfaces.pas
@@ -6,7 +6,7 @@ unit dddDomAuthInterfaces;
{
This file is part of Synopse mORMot framework.
- Synopse mORMot framework. Copyright (C) 2020 Arnaud Bouchez
+ Synopse mORMot framework. Copyright (C) 2022 Arnaud Bouchez
Synopse Informatique - https://synopse.info
*** BEGIN LICENSE BLOCK *****
@@ -25,7 +25,7 @@ unit dddDomAuthInterfaces;
The Initial Developer of the Original Code is Arnaud Bouchez.
- Portions created by the Initial Developer are Copyright (C) 2020
+ Portions created by the Initial Developer are Copyright (C) 2022
the Initial Developer. All Rights Reserved.
Contributor(s):
diff --git a/contrib/mORMot/SQLite3/DDD/dom/dddDomCountry.pas b/contrib/mORMot/SQLite3/DDD/dom/dddDomCountry.pas
index 3d202ae..ad8353e 100644
--- a/contrib/mORMot/SQLite3/DDD/dom/dddDomCountry.pas
+++ b/contrib/mORMot/SQLite3/DDD/dom/dddDomCountry.pas
@@ -6,7 +6,7 @@ unit dddDomCountry;
{
This file is part of Synopse mORMot framework.
- Synopse mORMot framework. Copyright (C) 2020 Arnaud Bouchez
+ Synopse mORMot framework. Copyright (C) 2022 Arnaud Bouchez
Synopse Informatique - https://synopse.info
*** BEGIN LICENSE BLOCK *****
@@ -25,7 +25,7 @@ unit dddDomCountry;
The Initial Developer of the Original Code is Arnaud Bouchez.
- Portions created by the Initial Developer are Copyright (C) 2020
+ Portions created by the Initial Developer are Copyright (C) 2022
the Initial Developer. All Rights Reserved.
Contributor(s):
diff --git a/contrib/mORMot/SQLite3/DDD/dom/dddDomEmailInterfaces.pas b/contrib/mORMot/SQLite3/DDD/dom/dddDomEmailInterfaces.pas
index 10aea0e..f5cc91d 100644
--- a/contrib/mORMot/SQLite3/DDD/dom/dddDomEmailInterfaces.pas
+++ b/contrib/mORMot/SQLite3/DDD/dom/dddDomEmailInterfaces.pas
@@ -1,4 +1,4 @@
-unit DomUserInterfaces;
+unit dddDomEmailInterfaces;
interface
diff --git a/contrib/mORMot/SQLite3/DDD/dom/dddDomUserCQRS.pas b/contrib/mORMot/SQLite3/DDD/dom/dddDomUserCQRS.pas
index e610f54..c351b43 100644
--- a/contrib/mORMot/SQLite3/DDD/dom/dddDomUserCQRS.pas
+++ b/contrib/mORMot/SQLite3/DDD/dom/dddDomUserCQRS.pas
@@ -6,7 +6,7 @@ unit dddDomUserCQRS;
{
This file is part of Synopse mORMot framework.
- Synopse mORMot framework. Copyright (C) 2020 Arnaud Bouchez
+ Synopse mORMot framework. Copyright (C) 2022 Arnaud Bouchez
Synopse Informatique - https://synopse.info
*** BEGIN LICENSE BLOCK *****
@@ -25,7 +25,7 @@ unit dddDomUserCQRS;
The Initial Developer of the Original Code is Arnaud Bouchez.
- Portions created by the Initial Developer are Copyright (C) 2020
+ Portions created by the Initial Developer are Copyright (C) 2022
the Initial Developer. All Rights Reserved.
Contributor(s):
diff --git a/contrib/mORMot/SQLite3/DDD/dom/dddDomUserInterfaces.pas b/contrib/mORMot/SQLite3/DDD/dom/dddDomUserInterfaces.pas
index 3039138..0bdb15c 100644
--- a/contrib/mORMot/SQLite3/DDD/dom/dddDomUserInterfaces.pas
+++ b/contrib/mORMot/SQLite3/DDD/dom/dddDomUserInterfaces.pas
@@ -6,7 +6,7 @@ unit dddDomUserInterfaces;
{
This file is part of Synopse mORMot framework.
- Synopse mORMot framework. Copyright (C) 2020 Arnaud Bouchez
+ Synopse mORMot framework. Copyright (C) 2022 Arnaud Bouchez
Synopse Informatique - https://synopse.info
*** BEGIN LICENSE BLOCK *****
@@ -25,7 +25,7 @@ unit dddDomUserInterfaces;
The Initial Developer of the Original Code is Arnaud Bouchez.
- Portions created by the Initial Developer are Copyright (C) 2020
+ Portions created by the Initial Developer are Copyright (C) 2022
the Initial Developer. All Rights Reserved.
Contributor(s):
diff --git a/contrib/mORMot/SQLite3/DDD/dom/dddDomUserTypes.pas b/contrib/mORMot/SQLite3/DDD/dom/dddDomUserTypes.pas
index 62e91b4..822f075 100644
--- a/contrib/mORMot/SQLite3/DDD/dom/dddDomUserTypes.pas
+++ b/contrib/mORMot/SQLite3/DDD/dom/dddDomUserTypes.pas
@@ -6,7 +6,7 @@ unit dddDomUserTypes;
{
This file is part of Synopse mORMot framework.
- Synopse mORMot framework. Copyright (C) 2020 Arnaud Bouchez
+ Synopse mORMot framework. Copyright (C) 2022 Arnaud Bouchez
Synopse Informatique - https://synopse.info
*** BEGIN LICENSE BLOCK *****
@@ -25,7 +25,7 @@ unit dddDomUserTypes;
The Initial Developer of the Original Code is Arnaud Bouchez.
- Portions created by the Initial Developer are Copyright (C) 2020
+ Portions created by the Initial Developer are Copyright (C) 2022
the Initial Developer. All Rights Reserved.
Contributor(s):
diff --git a/contrib/mORMot/SQLite3/DDD/infra/dddInfraApps.pas b/contrib/mORMot/SQLite3/DDD/infra/dddInfraApps.pas
index 29afa87..63e5d41 100644
--- a/contrib/mORMot/SQLite3/DDD/infra/dddInfraApps.pas
+++ b/contrib/mORMot/SQLite3/DDD/infra/dddInfraApps.pas
@@ -6,7 +6,7 @@ unit dddInfraApps;
{
This file is part of Synopse mORMot framework.
- Synopse mORMot framework. Copyright (C) 2020 Arnaud Bouchez
+ Synopse mORMot framework. Copyright (C) 2022 Arnaud Bouchez
Synopse Informatique - https://synopse.info
*** BEGIN LICENSE BLOCK *****
@@ -25,7 +25,7 @@ unit dddInfraApps;
The Initial Developer of the Original Code is Arnaud Bouchez.
- Portions created by the Initial Developer are Copyright (C) 2020
+ Portions created by the Initial Developer are Copyright (C) 2022
the Initial Developer. All Rights Reserved.
Contributor(s):
@@ -595,7 +595,8 @@ type
procedure ExecuteDisconnect;
procedure ExecuteDisconnectAfterError;
procedure ExecuteSocket;
- function TrySend(const aFrame: RawByteString; ImmediateDisconnectAfterError: boolean = true): Boolean; virtual;
+ function TrySend(const aFrame: RawByteString;
+ ImmediateDisconnectAfterError: boolean = true): Boolean; virtual;
// inherited classes could override those methods for process customization
procedure InternalExecuteConnected; virtual;
procedure InternalExecuteDisconnect; virtual;
diff --git a/contrib/mORMot/SQLite3/DDD/infra/dddInfraAuthRest.pas b/contrib/mORMot/SQLite3/DDD/infra/dddInfraAuthRest.pas
index d72747d..cfe359a 100644
--- a/contrib/mORMot/SQLite3/DDD/infra/dddInfraAuthRest.pas
+++ b/contrib/mORMot/SQLite3/DDD/infra/dddInfraAuthRest.pas
@@ -6,7 +6,7 @@ unit dddInfraAuthRest;
{
This file is part of Synopse mORMot framework.
- Synopse mORMot framework. Copyright (C) 2020 Arnaud Bouchez
+ Synopse mORMot framework. Copyright (C) 2022 Arnaud Bouchez
Synopse Informatique - https://synopse.info
*** BEGIN LICENSE BLOCK *****
@@ -25,7 +25,7 @@ unit dddInfraAuthRest;
The Initial Developer of the Original Code is Arnaud Bouchez.
- Portions created by the Initial Developer are Copyright (C) 2020
+ Portions created by the Initial Developer are Copyright (C) 2022
the Initial Developer. All Rights Reserved.
Contributor(s):
diff --git a/contrib/mORMot/SQLite3/DDD/infra/dddInfraEmail.pas b/contrib/mORMot/SQLite3/DDD/infra/dddInfraEmail.pas
index d107f62..f3dd27a 100644
--- a/contrib/mORMot/SQLite3/DDD/infra/dddInfraEmail.pas
+++ b/contrib/mORMot/SQLite3/DDD/infra/dddInfraEmail.pas
@@ -6,7 +6,7 @@ unit dddInfraEmail;
{
This file is part of Synopse mORMot framework.
- Synopse mORMot framework. Copyright (C) 2020 Arnaud Bouchez
+ Synopse mORMot framework. Copyright (C) 2022 Arnaud Bouchez
Synopse Informatique - https://synopse.info
*** BEGIN LICENSE BLOCK *****
@@ -25,7 +25,7 @@ unit dddInfraEmail;
The Initial Developer of the Original Code is Arnaud Bouchez.
- Portions created by the Initial Developer are Copyright (C) 2020
+ Portions created by the Initial Developer are Copyright (C) 2022
the Initial Developer. All Rights Reserved.
Contributor(s):
diff --git a/contrib/mORMot/SQLite3/DDD/infra/dddInfraEmailer.pas b/contrib/mORMot/SQLite3/DDD/infra/dddInfraEmailer.pas
index c5923ef..be11199 100644
--- a/contrib/mORMot/SQLite3/DDD/infra/dddInfraEmailer.pas
+++ b/contrib/mORMot/SQLite3/DDD/infra/dddInfraEmailer.pas
@@ -6,7 +6,7 @@ unit dddInfraEmailer;
{
This file is part of Synopse mORMot framework.
- Synopse mORMot framework. Copyright (C) 2020 Arnaud Bouchez
+ Synopse mORMot framework. Copyright (C) 2022 Arnaud Bouchez
Synopse Informatique - https://synopse.info
*** BEGIN LICENSE BLOCK *****
@@ -25,7 +25,7 @@ unit dddInfraEmailer;
The Initial Developer of the Original Code is Arnaud Bouchez.
- Portions created by the Initial Developer are Copyright (C) 2020
+ Portions created by the Initial Developer are Copyright (C) 2022
the Initial Developer. All Rights Reserved.
Contributor(s):
diff --git a/contrib/mORMot/SQLite3/DDD/infra/dddInfraRepoUser.pas b/contrib/mORMot/SQLite3/DDD/infra/dddInfraRepoUser.pas
index 2f10739..b5b8a8a 100644
--- a/contrib/mORMot/SQLite3/DDD/infra/dddInfraRepoUser.pas
+++ b/contrib/mORMot/SQLite3/DDD/infra/dddInfraRepoUser.pas
@@ -6,7 +6,7 @@ unit dddInfraRepoUser;
{
This file is part of Synopse mORMot framework.
- Synopse mORMot framework. Copyright (C) 2020 Arnaud Bouchez
+ Synopse mORMot framework. Copyright (C) 2022 Arnaud Bouchez
Synopse Informatique - https://synopse.info
*** BEGIN LICENSE BLOCK *****
@@ -25,7 +25,7 @@ unit dddInfraRepoUser;
The Initial Developer of the Original Code is Arnaud Bouchez.
- Portions created by the Initial Developer are Copyright (C) 2020
+ Portions created by the Initial Developer are Copyright (C) 2022
the Initial Developer. All Rights Reserved.
Contributor(s):
diff --git a/contrib/mORMot/SQLite3/DDD/infra/dddInfraSettings.pas b/contrib/mORMot/SQLite3/DDD/infra/dddInfraSettings.pas
index 053efd8..0c20842 100644
--- a/contrib/mORMot/SQLite3/DDD/infra/dddInfraSettings.pas
+++ b/contrib/mORMot/SQLite3/DDD/infra/dddInfraSettings.pas
@@ -6,7 +6,7 @@ unit dddInfraSettings;
{
This file is part of Synopse mORMot framework.
- Synopse mORMot framework. Copyright (C) 2020 Arnaud Bouchez
+ Synopse mORMot framework. Copyright (C) 2022 Arnaud Bouchez
Synopse Informatique - https://synopse.info
*** BEGIN LICENSE BLOCK *****
@@ -25,7 +25,7 @@ unit dddInfraSettings;
The Initial Developer of the Original Code is Arnaud Bouchez.
- Portions created by the Initial Developer are Copyright (C) 2020
+ Portions created by the Initial Developer are Copyright (C) 2022
the Initial Developer. All Rights Reserved.
Contributor(s):
diff --git a/contrib/mORMot/SQLite3/Documentation/Synopse SQLite3 Framework.pro b/contrib/mORMot/SQLite3/Documentation/Synopse SQLite3 Framework.pro
index faa7ec5..3d8423b 100644
--- a/contrib/mORMot/SQLite3/Documentation/Synopse SQLite3 Framework.pro
+++ b/contrib/mORMot/SQLite3/Documentation/Synopse SQLite3 Framework.pro
@@ -28,7 +28,7 @@ HtmlSideBar=Overview/Meet the mORMot:SOURCE,Download/How to install:TITL_113,API
; the sidebar first links, for html export
{\b Document License}
-{\i Synopse mORMot Framework Documentation}.\line Copyright (C) 2008-2020 Arnaud Bouchez.\line Synopse Informatique - @https://synopse.info
+{\i Synopse mORMot Framework Documentation}.\line Copyright (C) 2008-2022 Arnaud Bouchez.\line Synopse Informatique - @https://synopse.info
The {\i Synopse mORMot Framework Source Code} is licensed under GPL / LGPL / MPL licensing terms, free to be included in any application.
;This documentation has been generated using {\i Synopse SynProject} - @https://synopse.info/fossil/wiki?name=SynProject
;This document is a free document; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
@@ -136,7 +136,7 @@ The main approach of this framework is to avoid @*RAD@ in the development of pro
: Expected Use
Any application which need moderate database usage (up to some GB of data) with easy setup and administration, together with a secure @*ACID@ behavior in a Client-Server environment should consider using the {\i Synopse mORMot Framework}.
: Requirement Exceptions
-This framework was developed in order to run mainly under any {\i Delphi} compiler, from version {\i Delphi} 6 to version {\i Delphi 10.3 Rio}.
+This framework was developed in order to run mainly under any {\i Delphi} compiler, from version {\i Delphi} 6 to the latest Delphi version ({\i Delphi 11 Alexandria} at time of this writing).
On the {\i server side}, it targets both {\i Win32} and {\i Win64} platforms (using the 64-bit compiler included in latest {\i Delphi} XE2 and up).
For clients, in addition to those {\i Win32} / {\i Win64} platforms, you have cross-platform code generation abilities, for any {\i Delphi} or {\i @*FreePascal@} target (including {\i @*OSX@} and mobile {\i iOS} or {\i Android}), or AJAX / HTML5 clients via {\i @*Smart Mobile Studio@} - see @90@.
=[License]
@@ -464,7 +464,7 @@ The {\i Synopse mORMot Framework} shall provide User Interface and Report genera
Such a ribbon-oriented interface shall be made available, in a per-table approach, and associated reports.
Here is a sample of screen content, using proprietary TMS components:
%synfiletms.png
-And here is the same application compiled using only VCL components, available from {\i Delphi} 6 up to {\i Delphi 10.3 Rio}:
+And here is the same application compiled using only VCL components, available from {\i Delphi} 6 up to the latest available {\i Delphi} version:
%synfilevcl.png
[SRS-DI-2.3.1]
@@ -570,7 +570,7 @@ DisplayName=mORMot Framework Overview
:Synopse mORMot Overview
%IamLost.png
-{\i Synopse mORMot} is an Open Source @*Client-Server@ @*ORM@ @*SOA@ @*MVC@ framework for {\i Delphi} 6 up to {\i Delphi 10.3 Rio} and @*FPC@, targeting {\i Win/@*Linux@} for the server, and any platform for clients (including mobile or AJAX).
+{\i Synopse mORMot} is an Open Source @*Client-Server@ @*ORM@ @*SOA@ @*MVC@ framework for {\i Delphi} 6 up to the latest available {\i Delphi} version and @*FPC@ 3.2, targeting {\i Win/@*Linux@} for the server, and any platform for clients (including mobile or AJAX).
The main features of {\i mORMot} are therefore:
- {\i ORM/ODM}: objects persistence on almost any database (SQL or NoSQL);
- {\i SOA}: organize your business logic into @*REST@ services;
@@ -708,7 +708,7 @@ At first, some points can be highlighted, which make this framework distinct to
- More than 1800 pages of documentation;
- {\i Delphi}, {\i FreePascal}, mobile and @*AJAX@ clients can share the same server, and ORM/SOA client access code can be generated on request for any kind of application - see @86@;
- Full source code provided - so you can enhance it to fulfill any need;
-- Works from {\i Delphi} 6 up to {\i Delphi 10.3 Rio} and FPC 2.6.4/2.7.1/3.x, truly Unicode (uses @*UTF-8@ encoding in its kernel, just like JSON), with any version of {\i Delphi} (no need to upgrade your IDE).
+- Works from {\i Delphi} 6 up to the latest available {\i Delphi} version and FPC 3.2.x, truly Unicode (uses @*UTF-8@ encoding in its kernel, just like JSON), with any version of {\i Delphi} (no need to upgrade your IDE).
\page
: Benefits
As you can see from the previous section, {\i mORMot} provides a comprehensive set of features that can help you to manage your crosscutting concerns though a reusable set of components and core functionality.
@@ -1364,7 +1364,7 @@ In the following next paragraphs, we'll comment some main features of the lowest
- {\f1\fs20 @*TDocVariant@} custom {\f1\fs20 variant} type for dynamic schema-less {\i object} or {\i array} storage.
Other shared features available in {\f1\fs20 SynTests.pas} and {\f1\fs20 SynLog.pas} will be detailed later, i.e. @*Test@ing and @*Log@ging - see @12@.
:32 Unicode and UTF-8
-Our {\i mORMot} Framework has 100% UNICODE compatibility, that is compilation under {\i Delphi} 2009 and up (including latest {\i Delphi 10.3 Rio} revision). The code has been deeply rewritten and @*test@ed, in order to provide compatibility with the {\f1\fs20 String=UnicodeString} paradigm of these compilers. But the code will also handle safely Unicode for older versions, i.e. from {\i Delphi} 6 up to {\i Delphi} 2007.
+Our {\i mORMot} Framework has 100% UNICODE compatibility, that is compilation under {\i Delphi} 2009 and up (including the latest available {\i Delphi} version). The code has been deeply rewritten and @*test@ed, in order to provide compatibility with the {\f1\fs20 String=UnicodeString} paradigm of these compilers. But the code will also handle safely Unicode for older versions, i.e. from {\i Delphi} 6 up to {\i Delphi} 2007.
From its core to its uppermost features, our framework is natively @**UTF-8@, which is the de-facto character encoding for @*JSON@, {\i @*SQLite3@}, and most supported database engines. This allows our code to offer fast streaming/parsing in a @*SAX@-like mode, avoiding any conversion between encodings from the storage layer to your business logic. We also needed to establish a secure way to use strings, in order to handle all versions of {\i Delphi} (even pre-Unicode versions, especially the {\i Delphi} 7 version we like so much), and provide compatibility with the {\i @*FreePascal@ Compiler}. This consistency allows to circumvent any RTL bug or limitation, and ease long-term support of your project.
Some string types have been defined, and used in the code for best cross-compiler efficiency:
- {\f1\fs20 @**RawUTF8@} is used for every internal data usage, since both {\i SQLite3} and JSON do expect UTF-8 encoding;
@@ -1463,7 +1463,7 @@ Here is how those new methods work:
! if GroupA.Find(v)<0 then // fast binary search
! ShowMessage('Error: 1500 not found!');
Some unique methods like {\f1\fs20 Slice, Reverse} or {\f1\fs20 AddArray} are also available, and mimic well-known Python methods.
-Still closer to the generic paradigm, working for {\i Delphi} 6 up to {\i Delphi 10.3 Rio}, without the need of the slow enhanced RTTI, nor the executable size overhead and compilation issues of generics...
+Still closer to the generic paradigm, working for {\i Delphi} 6 up to the latest available {\i Delphi} version, without the need of the slow enhanced RTTI, nor the executable size overhead and compilation issues of generics...
: Capacity handling via an external Count
One common speed issue with the default usage of {\f1\fs20 TDynArray} is that the internal memory buffer is reallocated when you change its length, just like a regular {\i Delphi} {\i dynamic array}.
That is, whenever you call {\f1\fs20 Add} or {\f1\fs20 Delete} methods, an internal call to {\f1\fs20 SetLength(DynArrayVariable)} is performed. This could be slow, because it always executes some extra code, including a call to {\f1\fs20 ReallocMem}.
@@ -1829,7 +1829,7 @@ When working with complex documents, e.g. with @*BSON@ / {\i @*MongoDB@} documen
: Advanced TDocVariant process
:194 Number values options
By default, {\f1\fs20 TDocVariantData} will only recognize {\f1\fs20 integer}, {\f1\fs20 Int64} and {\f1\fs20 currency} - see @33@ - as number values. Any floating point value which may not be translated to/from @*JSON@ textual representation safely will be stored as a JSON string, i.e. if it does match an integer or up to 4 fixed decimals, with 64-bit precision. We stated that JSON serialization should be conservative, i.e. serializing then unserializing (or the other way round) should return the very same value; parsing JSON is a matter of (difficult) choices - see @http://seriot.ch/parsing_json.php#5 - and we choose to be paranoid and not loose information by default.
-You can set the {\f1\fs20 @*dvoAllowDoubleValue@} option to {\f1\fs20 TDocVariantData}, so that such floating-point numbers will be recognized and stored as {\f1\fs20 @*double@}. In this case, only {\f1\fs20 varDouble} storage will be used for the {\f1\fs20 variant} values, i.e. 64-bit IEEE 754 {\f1\fs20 double} values, handling 5.0 x 10^-324 .. 1.7 x 10^308 range. With such floating-point values, you may loose precision and digits during the JSON serialization process: this is why it is not enabled by default.
+You can use the {\f1\fs20 @*_JsonFastFloat()@} wrapper or set the {\f1\fs20 @**dvoAllowDoubleValue@} option to {\f1\fs20 TDocVariantData}, so that such floating-point numbers will be recognized and stored as {\f1\fs20 @**double@}. In this case, only {\f1\fs20 varDouble} storage will be used for the {\f1\fs20 variant} values, i.e. 64-bit IEEE 754 {\f1\fs20 double} values, handling 5.0 x 10^-324 .. 1.7 x 10^308 range. With such floating-point values, you may loose precision and digits during the JSON serialization process: this is why it is not enabled by default.
Also note that some JSON engines do not support 64-bit integer numbers. For instance, {\f1\fs20 @*JavaScript@} engines handle only up to @*53-bit@ of information without precision loss (called the {\i significand} bits), due to their internal storage as a 8 bytes IEEE 754 container. In some cases, it is safest to use JSON string representation of such numbers, as is done with the {\f1\fs20 woIDAsIDstr} value of {\f1\fs20 TTextWriterWriteObjectOption} for safe serialization of {\f1\fs20 TSQLRecord.ID} ORM values.
If you want to work with high-precision floating point numbers, consider using {\f1\fs20 @*TDecimal128@} values, as implemented in {\f1\fs20 SynMongoDB.pas}, which supports 128-bit high precision decimal, as defined by the {\i IEEE 754-2008 128-bit decimal floating point} standard, and handled in {\i MongoDB} 3.4+. Their conversion to/from text - therefore to/from JSON - won't loose nor round any digit, as soon as the value fits in its 128-bit storage.
: Object or array document creation options
@@ -4610,7 +4610,7 @@ In the above query expression, the {\f1\fs20 rank()} function is used over the d
In any database, there is a need to define how column data is to be compared. It is needed for proper search and ordering of the data. This is the purpose of so-called {\i @**collation@s}.
By default, when {\i SQLite} compares two strings, it uses a collating sequence or collating function (two words for the same thing) to determine which string is greater or if the two strings are equal. {\i SQLite} has three built-in collating functions: BINARY, NOCASE, and RTRIM:
- BINARY - Compares string data using {\f1\fs20 memcmp()}, regardless of text encoding.
-- NOCASE - The same as binary, except the 26 upper case characters of ASCII are folded to their lower case equivalents before the comparison is performed. Note that only ASCII characters are case folded. Plain {\i SQLite} does not attempt to do full @*Unicode@ case folding due to the size of the tables required - but you could use {\i mORMot}'s SYSTEMNOCASE or WIN32CASE/WIN32NOCASE custom collations for enhanced case folding support (see below);
+- NOCASE - The same as binary, except the 26 upper case characters of ASCII are folded to their lower case equivalents before the comparison is performed. Note that only ASCII characters are case folded. Plain {\i SQLite} does not attempt to do full @*Unicode@ case folding due to the size of the tables required - but you could use {\i mORMot}'s SYSTEMNOCASE, or WIN32CASE/WIN32NOCASE custom collations for enhanced case folding support (see below);
- RTRIM - The same as binary, except that trailing space characters are ignored.
In the {\i mORMot} ORM, we defined some additional kind of collations, via some internal calls to the {\f1\fs20 sqlite3_create_collation()} API:
|%25%60
@@ -4632,6 +4632,7 @@ The following collations are therefore available when using {\i SQLite3} within
|NOCASE|Default ASCII 7 bit comparison
|RTRIM|Default {\f1\fs20 memcmp()} comparison with right trim
|SYSTEMNOCASE|{\i mORMot}'s Win-1252 8 bit comparison
+;|UNICODENOCASE|{\i mORMot}'s Unicode 10.0 comparison
|ISO8601|{\i mORMot}'s date/time comparison
|WIN32CASE|{\i mORMot}'s comparison using case-insensitive Windows API
|WIN32NOCASE|{\i mORMot}'s comparison using not case-insensitive Windows API
@@ -4639,17 +4640,17 @@ The following collations are therefore available when using {\i SQLite3} within
Note that WIN32CASE/WIN32NOCASE will be slower than the others, but will handle properly any kind of complex scripting. For instance, if you want to use the Unicode-ready Windows API at database level, you can set for each database model:
! aModel.SetCustomCollationForAll(sftUTF8Text,'WIN32CASE');
! aModel.SetCustomCollationForAll(sftDateTime,'NOCASE');
+On non-Windows platform, it will either use the system ICU library (if available), or fallback to the FPC RTL with temporary {\f1\fs20 UnicodeString} values - which requires to include `cwstrings` in your project uses clause. Note that depending on the library used, the results may not be consistent: so if you move a {\i SQLite3} database file e.g. from a Windows system to a Linux system with WIN32CASE collation, you should better regenerate all your indexes!
If you use non-default collations (i.e. SYSTEMNOCASE/ISO8601/WIN32CASE/WIN32NOCASE), you may have trouble running requests with "plain" {\i SQLite3} tools. But you can use our {\f1\fs20 @*SynDBExplorer@} safely, since it will declare all the above collations.
When using external databases - see @27@, if the content is retrieved directly from the database driver and by-passes the virtual table mechanism - see @20@, returned data may not match your expectations according to the custom collations: you will need to customize the external tables definition by hand, with the proper SQL statement of each external DB engine.
+Note that {\i @*mORMot 2@} offers a new UNICODENOCASE collation, which follows Unicode 10.0 without any Windows or ICU API call, so is consistent on all systems - and is also faster.
: REGEXP operator
-Our {\i SQLite3} engine can use {\i @**regular expression@} within its SQL queries, by enabling the {\f1\fs20 @**REGEXP@} operator in addition to standard SQL operators ({\f1\fs20 = == != <> IS IN LIKE GLOB MATCH}). It will use the Open Source PCRE library to perform the queries.
-In order to enable the operator, you should include unit {\f1\fs20 SynSQLite3RegEx.pas} to your uses clause, and register the {\f1\fs20 RegExp()} SQL function to a given {\i SQLite3} database instance, as such:
-!uses SynCommons, mORmot, mORMotSQLite3,
-!! SynSQLite3RegEx;
-! ...
+Our {\i SQLite3} engine can use {\i @**regular expression@} within its SQL queries, by enabling the {\f1\fs20 @**REGEXP@} operator in addition to standard SQL operators ({\f1\fs20 = == != <> IS IN LIKE GLOB MATCH}).
+: Default REGEXP Engine
+By default, and since mORMot 1.18.6218 (25 January 2021), our static {\i SQlite3} engine includes a compact and efficient enough C extension, as available from the official {\i SQLite3} project source code tree. It is included with the official amalgamation file during our compilation phase.
+So you don't need to do anything to be able to use the REGEX operator in your queries:
!Server := TSQLRestServerDB.Create(Model,'test.db3');
!try
-!! CreateRegExpFunction(Server.DB.DB);
! with TSQLRecordPeople.CreateAndFillPrepare(Client,
!! 'FirstName REGEXP ?',['\bFinley\b']) do
! try
@@ -4667,6 +4668,20 @@ The above code will execute the following SQL statement (with a prepared paramet
! SELECT * from People WHERE Firstname REGEXP '\bFinley\b';
That is, it will find all objects where {\f1\fs20 TSQLRecordPeople.FirstName} will contain the {\f1\fs20 'Finley'} word - in a regular expression, {\f1\fs20 \\b} defines a word {\f1\fs20 b}oundary search.
In fact, the {\f1\fs20 REGEXP} operator is a special syntax for the {\f1\fs20 regexp()} user function. No {\f1\fs20 regexp()} user function is defined by default and so use of the {\f1\fs20 REGEXP} operator will normally result in an error message. Calling {\f1\fs20 CreateRegExFunction()} for a given connection will add a SQL function named "{\f1\fs20 regexp()}" at run-time, which will be called in order to implement the {\f1\fs20 REGEXP} operator.
+: PCRE REGEXP Engine
+If you want to use the Open Source PCRE library to perform the searches, instead of this default C extension, you should include the {\f1\fs20 SynSQLite3RegEx.pas} unit to your uses clause, and register the {\f1\fs20 RegExp()} SQL function to a given {\i SQLite3} database instance, as such:
+!uses SynCommons, mORmot, mORMotSQLite3,
+!! SynSQLite3RegEx;
+! ...
+!Server := TSQLRestServerDB.Create(Model,'test.db3');
+!try
+!! CreateRegExpFunction(Server.DB.DB);
+! with TSQLRecordPeople.CreateAndFillPrepare(Client,
+!! 'FirstName REGEXP ?',['\bFinley\b']) do
+! try
+! while FillOne do begin
+! Check(LastName='Morse');
+! ...
It will use the statically linked PCRE library as available since {\i Delphi} XE, or will rely on the {\f1\fs20 PCRE.pas} wrapper unit as published at @http://www.regular-expressions.info/download/TPerlRegEx.zip for older versions of {\i Delphi}.
This unit will call directly the @*UTF-8@ API of the PCRE library, and maintain a per-connection cache of compiled regular expressions to ensure the best performance possible.
:60 ACID and speed
@@ -4752,7 +4767,8 @@ Note that the virtual table module name is retrieved from the class name. For in
To handle external databases, two dedicated classes, named {\f1\fs20 TSQLVirtualTableExternal} and {\f1\fs20 TSQLVirtualTableCursorExternal} will be defined in a similar manner - see @%%HierExternalTables@ @30@.
As you probably have already stated, all those Virtual Table mechanism is implemented in {\f1\fs20 mORMot.pas}. Therefore, it is independent from the {\i @*SQLite3@} engine, even if, to my knowledge, there is no other SQL database engine around able to implement this pretty nice feature.
: Defining a Virtual Table module
-Here is how the {\f1\fs20 TSQLVirtualTableLog} class type is defined, which will implement a @*Virtual Table@ module named "{\f1\fs20 Log}". Adding a new module is just made by overriding some {\i Delphi} methods:
+Here is how the {\f1\fs20 TSQLVirtualTableLog} class type is defined, which will implement a @*Virtual Table@ module named "{\f1\fs20 Log}". Note that the {\i SQLite3} virtual table module name will be computed from the class name, trimming its first characters, e.g. {\f1\fs20 TSQLVirtualTable{\b Log}} will trim trailing {\f1\fs20 TSQLVirtualTable} and define a {\f1\fs20 'Log'} virtual module.
+Adding a new module is just made by overriding some {\i Delphi} methods:
! TSQLVirtualTableLog = class(TSQLVirtualTable)
! protected
! fLogFile: TSynLogFile;
@@ -7431,7 +7447,7 @@ In practice, for your project, you will have several possibilities to create a C
|SOA Interfaces|RPC REST|RPC
|SOA Methods|Full REST/HTTP|Verbose
|MVC Web|Web site + AJAX|HTML-oriented
-|ORM REST|Tests or internal use|Security/design flows
+|ORM REST|Tests or internal use|Security/design flaws
|%
In a nutshell,
- {\i SOA Interfaces} - see @63@ - is the preferred way to build both public and private services: both client and server code will be defined from {\f1\fs20 interface} types, including sessions management, stubbing/mocking, documentation generation, and security features.
@@ -9668,7 +9684,7 @@ If you compare with existing mocking frameworks, even in other languages / platf
- Most common parameters and results can be defined as simple {\f1\fs20 array of const} in the {\i Delphi} code, or by supplying JSON arrays (needed e.g. for more complex structures like {\f1\fs20 record} values);
- Execution trace retrieval in easy to read or write text format (and not via complex "fluent" interface e.g. with {\f1\fs20 When} clauses);
- Auto-release of the {\f1\fs20 TInterfaceStub TInterfaceMock TInterfaceMockSpy} generator instance, when the interface is no longer required, to minimize the code to type, and avoid potential memory leaks;
-- Works from {\i Delphi} 6 up to {\i Delphi 10.3 Rio} - since no use of syntax sugar like generics, nor the {\f1\fs20 RTTI.pas} features;
+- Works from {\i Delphi} 6 up to the latest available {\i Delphi} version - since no use of syntax sugar like generics, nor the {\f1\fs20 RTTI.pas} features;
- Very good performance (the faster {\i Delphi} mocking framework, for sure), due to very low overhead and its reuse of {\i mORMot}'s low-level interface-based services kernel using JSON serialization, which does not rely on the slow and limited {\f1\fs20 TVirtualInterface}.
: Stubbing complex return values
Just imagine that the {\f1\fs20 ForgotMyPassword} method does perform an internal test:
@@ -9881,7 +9897,7 @@ Here are the key features of the current implementation of services using interf
|Server factory|You can get an implementation on the server side
|Client factory|You can get a "fake" implementation on the client side, remotely calling the server to execute the process
|Cross-platform clients|A {\i mORMot} server is able to generate cross-platform client code via a set of templates - see @86@
-|Auto marshalling|The contract is transparently implemented: no additional code is needed e.g. on the client side, and will handle simple types (strings, numbers, dates, sets and enumerations) and high-level types (objects, collections, records, dynamic arrays, variants) from {\i Delphi} 6 up to {\i Delphi 10.3 Rio}
+|Auto marshalling|The contract is transparently implemented: no additional code is needed e.g. on the client side, and will handle simple types (strings, numbers, dates, sets and enumerations) and high-level types (objects, collections, records, dynamic arrays, variants) from {\i Delphi} 6 up to the latest available {\i Delphi} version
|Flexible|Methods accept per-value or per-reference parameters
|Instance lifetime|An implementation class can be:\line - Created on every call,\line - Shared among all calls,\line - Shared for a particular user or group,\line - Dedicated to the thread it runs on,\line - Alive as long as the client-side interface is not released,\line - Or as long as an @*authentication@ session exists
|@*Stateless@|Following a standard request/reply pattern
@@ -9983,7 +9999,7 @@ You can therefore define complex {\f1\fs20 interface} types, as such:
! /// validates ArgsInputIsOctetStream raw binary upload
! function DirectCall(const Data: TSQLRawBlob): integer;
! end;
-Note how {\f1\fs20 SpecialCall} and {\f1\fs20 ComplexCall} methods have quite complex parameters definitions, including dynamic arrays, sets and records. DirectCall will use binary POST, by-passing @*Base64@ JSON encoding - see @197@. The framework will handle {\f1\fs20 const} and {\f1\fs20 var} parameters as expected, i.e. as input/output parameters, also on the client side. Any simple types of dynamic arrays (like {\f1\fs20 TIntegerDynArray}, {\f1\fs20 TRawUTF8DynArray}, or {\f1\fs20 TWideStringDynArray}) will be serialized as plain JSON arrays - the framework is able to handle any dynamic array definition, but will serialize those simple types in a more AJAX compatible way, thanks to the enhanced RTTI available since to {\i Delphi} 2010.
+Note how {\f1\fs20 SpecialCall} and {\f1\fs20 ComplexCall} methods have quite complex parameters definitions, including dynamic arrays, sets and records. {\f1\fs20 DirectCall} will use binary POST, by-passing @*Base64@ JSON encoding - see @197@. The framework will handle {\f1\fs20 const} and {\f1\fs20 var} parameters as expected, i.e. as input/output parameters, also on the client side. Any simple types of dynamic arrays (like {\f1\fs20 TIntegerDynArray}, {\f1\fs20 TRawUTF8DynArray}, or {\f1\fs20 TWideStringDynArray}) will be serialized as plain JSON arrays - the framework is able to handle any dynamic array definition, but will serialize those simple types in a more AJAX compatible way, thanks to the enhanced RTTI available since to {\i Delphi} 2010.
: TPersistent / TSQLRecord parameters
As stated above, {\i mORMot} does not allow a method {\f1\fs20 function} to return a {\f1\fs20 class} instance.
That is, you can't define such a method:
@@ -13659,7 +13675,7 @@ By default, the following security groups are created on a void database:
|%14%12%14%11%11%12%12%12
|\b Group|POST SQL|SELECT SQL|Auth R|Auth W|Tables R|Tables W|Services\b0
|Admin|Yes|Yes|Yes|Yes|Yes|Yes|Yes
-|Supervisor|Yes|No|Yes|No|Yes|Yes|Yes
+|Supervisor|No|Yes|Yes|No|Yes|Yes|Yes
|User|No|No|No|No|Yes|Yes|Yes
|Guest|No|No|No|No|Yes|No|No
|%
@@ -15736,7 +15752,7 @@ And even better, testing-driven coding can be encouraged:
It could sounds like a waste of time, but such coding improve your code quality a lot, and, at least, it help you write and optimize every implementation feature.
The framework has been implemented using this approach, and provide all the tools to write tests. In addition to what other {\i Delphi} frameworks offer (e.g. {\i DUnit / DUnitX}), the {\f1\fs20 SynTests.pas} unit is very much integrated with other elements of the framework (like logging), is cross-platform and cross-compiler, and provides a complete {\i stubbing / mocking} mechanism to cover @62@.
: Involved classes in Unitary testing
-The @!TSynTest,TSynTestCase,TSynTests!Lib\SynTests.pas@ unit defines two classes (both inheriting from {\f1\fs20 TSynTest}), implementing a complete Unitary testing mechanism similar to {\i DUnit}, with less code overhead, and direct interface with the framework units and requirements (@*UTF-8@ ready, code compilation from {\i Delphi} 6 up to {\i Delphi 10.3 Rio} and FPC, no external dependency).
+The @!TSynTest,TSynTestCase,TSynTests!Lib\SynTests.pas@ unit defines two classes (both inheriting from {\f1\fs20 TSynTest}), implementing a complete Unitary testing mechanism similar to {\i DUnit}, with less code overhead, and direct interface with the framework units and requirements (@*UTF-8@ ready, code compilation from {\i Delphi} 6 up to the latest available {\i Delphi} version and FPC, no external dependency).
The following diagram defines this class hierarchy:
\graph HierTSynTest TSynTest classes hierarchy
\TSynTests\TSynTest
@@ -15850,12 +15866,10 @@ Before any release all unitary regression tests are performed with the following
- {\i Delphi} 2007;
- {\i Delphi} 2010 (we assume that if it works with {\i Delphi} 2010, it will work with {\i Delphi} 2009, with the exception of {\f1\fs20 generic} compilation);
- {\i Delphi} XE4;
-- {\i Delphi} XE6;
- {\i Delphi} XE7;
-- {\i Delphi} 10 Seattle;
-- {\i Delphi} 10.1 Berlin;
-- {\i Delphi} 10.2 Tokyo;
+- {\i Delphi} XE8;
- {\i Delphi} 10.3 Rio;
+- {\i Delphi} 10.4 Sidney;
- {\i @*CrossKylix@} 3.0;
- {\i @*FPC@} 3.x - preferred is {\i 3.2 fixes}.
Target platforms are {\i Win32} and {\i Win64} for {\i Delphi} and {\i FPC}, plus {\i Linux 32/64} for {\i FPC} and {\i CrossKylix}.
@@ -16223,17 +16237,17 @@ Follow these steps:
- Finally, click on the "{\i Zip Archive}" link, available at the end of the "{\i Overview}" header, right ahead to the "{\i Other Links}" title. This link will build a {\f1\fs20 .zip} archive of the complete source code and download it to your browser.
: Expected compilation platform
The framework source code tree will compile and is tested for the following platforms:
-- {\i Delphi} 6 up to {\i Delphi 10.3 Rio} compiler and IDE, with {\i @*FreePascal@ Compiler} (FPC) 3.x and {\i @*Lazarus@} support;
+- {\i Delphi} 6 up to the latest {\i Delphi} compiler and IDE version, with {\i @*FreePascal@ Compiler} (FPC) 3.x and {\i @*Lazarus@} support;
- Server side on Windows 32-bit and @**64-bit@ platforms (FPC or {\i Delphi} XE2 and up expected when targeting {\i Win64});
- {\i @*Linux@} 32-bit and 64-bit platform for servers using the FPC 3.2 fixes branch - now stable and tested in production since years (especially {\i @*Debian@/@*Ubuntu@} on {\f1\fs20 x86_64});
- VCL client on Win32/Win64 - GUI may be compiled optionally with third-party non Open-Source @*TMS@ Components, instead of default VCL components - see @http://www.tmssoftware.com/site/tmspack.asp
- @69@ clients on any supported platforms;
- @90@ startup with 2.1, for creating @*AJAX@ / @*JavaScript@ / HTML5 / Mobile clients.
Some part of the library (e.g. {\f1\fs20 SynCommons.pas}, {\f1\fs20 SynTests.pas}, {\f1\fs20 SynLog.pas} {\f1\fs20 SynPDF.pas} or the @27@ units) are also compatible with {\i Delphi} 5.
-If you want to compile {\i mORMot} unit into @*packages@, to avoid an obfuscated {\i [DCC Error] @*E2201@ Need imported data reference ($G) to access 'VarCopyProc'} error at compilation, you should defined the {\f1\fs20 USEPACKAGES} conditional in your project's options. Open {\f1\fs20 SynCommons.inc} for a description of this conditional, and all over definitions global to all {\i mORMot} units - see @45@.
+If you want to compile {\i mORMot} unit into @**packages@, to avoid an obfuscated {\i [DCC Error] @*E2201@ Need imported data reference ($G) to access 'VarCopyProc'} error at compilation, you should defined the {\f1\fs20 USEPACKAGES} conditional in your project's options. Open {\f1\fs20 SynCommons.inc} for a description of this conditional, and all over definitions global to all {\i mORMot} units - see @45@. To avoid related {\i @*E1025@ Unsupported language feature: 'Object'} compilation error, you should probably also set "{\i Generate DCUs only}" in project's options "{\i C/C++ output file generator}".
The framework source code implementation and design tried to be as cross-platform and cross-compiler as possible, since the beginning. It is a lot of work to maintain compatibility towards so many tools and platforms, but we think it is always worth it - especially if you try not depend on {\i Delphi} only, which as shown some backward compatibility issues during its lifetime.
For HTML5 and Mobile clients, our main platform is {\i Smart Mobile Studio}, which is a great combination of ease of use, a powerful {\i SmartPascal} dialect, small applications (much smaller than FMX), with potential packaging as native iOS or {\i Android} applications (via {\i @*PhoneGap@}).
-The latest versions of the {\i FreePascal Compiler} together with its great {\i Lazarus} IDE, are now very stable and easy to work with. We don't support {\i CodeTyphon}, since we found some licensing issue with some part of it (e.g. {\i Orca} GUI library origin is doubtful). So we recommend using {\i @*fpcupdeluxe@} - see @203@ - which is maintained by Alfred, a {\i mORMot} contributor. This is amazing to build the whole set of compilers and IDE, with a lot of components, for several platforms (this is a cross-platform project), just from the sources. I like {\i Lazarus} stability and speed much more than {\i Delphi} (did you ever tried to browse and debug {\i included} {\f1\fs20 $I ...} files in the {\i Delphi} IDE? with Lazarus, it is painless), even if the compiler is slower than {\i Delphi}'s, and if the debugger is less integrated and even more unstable than {\i Delphi}'s under Windows (yes, it is possible!). At least, it works, and the {\i Lazarus} IDE is small and efficient. Official {\i @*Linux@} support is available for {\i mORMot} servers, with full features in the {\i FPC} 3.2 branch - we use it on producing on {\i Linux} 64-bit since years.
+The latest versions of the {\i FreePascal Compiler} together with its great {\i Lazarus} IDE, are now very stable and easy to work with. We don't support {\i CodeTyphon}, since we found some licensing issue with some part of it (e.g. {\i Orca} GUI library origin is doubtful). So we recommend using {\i @*fpcupdeluxe@} - see @203@ - which is maintained by Alfred, a {\i mORMot} contributor. This is amazing to build the whole set of compilers and IDE, with a lot of components, for several platforms (this is a cross-platform project), just from the sources. I like {\i Lazarus} stability and speed much more than {\i Delphi} (did you ever tried to browse and debug {\i included} {\f1\fs20 $I ...} files in the {\i Delphi} IDE? with Lazarus, it is painless), even if the compiler is slower than {\i Delphi}'s, and if the debugger is less integrated and even more unstable than {\i Delphi}'s under Windows (yes, it is possible!). At least, it works, and the {\i Lazarus} IDE is small and efficient. Official {\i @*Linux@} support is available for {\i mORMot} servers, with full features in the {\i FPC} 3.2 branch - we use it on production with {\i Linux} 64-bit since years.
: SQLite3 static linking for Delphi and FPC
{\i Preliminary note}: if you retrieved the source code from @https://github.com/synopse/mORMot you will have all the needed {\f1\fs20 .obj/.o} static files available in the expected folders. Just ignore this chapter.
In order to maintain our @https://synopse.info/fossil/timeline source code repository in a decent size, we excluded the {\f1\fs20 sqlite3.obj/.o} storage in it, but provide the full source code of the {\i @*SQlite3@} engine in a custom {\f1\fs20 sqlite3.c} file, ready to be compiled with all conditional defined as expected by {\f1\fs20 SynSQlite3Static.pas}. You need to add the official {\i SQlite3} amalgamation file from @https://www.sqlite.org/download.html and put its content into a {\f1\fs20 SQLite3\\amalgamation} sub-folder, for proper compilation. Our custom {\f1\fs20 sqlite3.c} file will add encryption feature to the engine. Also look into {\f1\fs20 SynSQlite3Static.pas} comments if there is any manual patch needed for proper compilation of the amalgamation sourece.
@@ -16374,7 +16388,7 @@ See @86@ for more information.
\page
:113 Delphi Installation
{\i Note: for FPC setup, see @125@.}
-To setup mORMot for {\i Delphi 6} up to {\i Delphi 10.3 Rio}, you have two ways: either download the framework from archives, or clone our {\i GitHub} repository at @https://github.com/synopse/mORMot
+To setup mORMot for {\i Delphi 6} up to the latest {\i Delphi} version, you have two ways: either download the framework from archives, or clone our {\i GitHub} repository at @https://github.com/synopse/mORMot
: Manual download
Download and uncompress the framework archives, including all sub-folders, into a local directory of your computer (for instance, {\f1\fs20 D:\\Dev\\mORMot}).
|%70
@@ -16429,11 +16443,12 @@ But since the FPC trunk may be unstable, we will propose to put in place a stabl
For this task, don't download an existing binary release of FPC / Lazarus, but use the {\i @**fpcupdeluxe@} tool, as published at @http://wiki.freepascal.org/fpcupdeluxe - it will allow to build your environment directly from the sources, and install it in a dedicated folder. Several FPC / Lazarus installations, with dedicated revision numbers, may coexist on the same computer: just ensure you run Lazarus from the shortcut created by {\i fpcupdeluxe}.
- Download the latest release of the tool from @https://github.com/LongDirtyAnimAlf/fpcupdeluxe/releases
- Unpack it in a dedicated folder, and run its executable.
-- On the main screen, locate on the left the two versions listboxes. Select "fixes" for both {\i FPC version} and {\i Lazarus version}.
+- On the main screen, locate on the left the two versions listboxes. Select "{\f1\fs20 3.2}" for {\i FPC version} and "{\f1\fs20 2.1.0}" for {\i Lazarus version}.
+- Important note: if you want to cross-compile from Windows to other systems, e.g. install a Linux cross-compiler on Windows, ensure you installed the {\i Win32} FPC compiler and Lazarus, {\i not the Win64} version, which is known to have troubles with {\f1\fs20 currency} support;
- Then build the FPC and Lazarus binaries directly from the latest sources, by clicking on "Install/update FPC+Laz".
-Those "fixes" branches are currently used for building our production projects, so are expected to be properly tested and supported. \line At the time of the writing of this documentation, our Lazarus IDE (on Linux) reports using:
-- FPC fixes SVN 45428 (3.2.0)
-- Lazarus fixes SVN 63179 (2.0.9).
+Those branches are currently used for building our production projects, so are expected to be properly tested and supported. \line At the time of the writing of this documentation, our Lazarus IDE (on Linux) reports using:
+- FPC SVN 45643 (3.2.0)
+- Lazarus SVN 64940 (2.1.0).
One big advantage of {\i fpcupdeluxe} is that you can very easily install cross-compilers for the CPU / OS combinations enumerated at @202@.\line Just go to the "Cross" tab, then select the target systems, and click on "Install compiler".\line It may be needed to download the cross-compiler binaries (once): just select "Yes" when prompted.
You could install {\i mORMot} using {\i fpcupdeluxe}, but we recommend you clone our @https://github.com/synopse/mORMot repository, and setup the expected project paths, as detailed above at @113@.
If you don't want to define a given version, the current {\i trunk} should/could work, if it didn't include any regression at the time you get it - this is why we provide "supported" branches.\line If you want to use the {\i FPC trunk}, please modify line #262 in {\f1\fs20 Synopse.inc} to enable the {\f1\fs20 FPC_PROVIDE_ATTR_TABLE} conditional and support the latest trunk RTTI changes:
@@ -16839,7 +16854,7 @@ The {\i Office UI licensing program} was designed by {\i Microsoft} for software
If you want to design your user interface using a Office 2007/2010 ribbon look, please take a look at those official guidelines: @http://msdn.microsoft.com/en-us/library/cc872782.aspx
Here is the screen content, using the TMS components:
%synfiletms.png
-And here is the same application compiled using only VCL components, available from {\i Delphi} 6 up to {\i Delphi 10.3 Rio}:
+And here is the same application compiled using only VCL components, available from {\i Delphi} 6 up to the latest {\i Delphi} version:
%synfilevcl.png
We did not use yet the Ribbon component as was introduced in {\i Delphi} 2009. Its action-driven design won't make it easy to interface with the event-driven design of our User Interface handling, and we have to confess that this component has rather bad reputation (at least in the {\i Delphi} 2009 version). Feel free to adapt our Open Source code to use it - we'll be very pleased to release a new version supporting it, but we don't have time nor necessity to do it by ourself.
: Enumeration types
@@ -18465,7 +18480,7 @@ But please do not forget to put somewhere in your credit window or documentation
For instance, if you select the MPL license, here are the requirements:
- You accept the license terms with no restriction - see @http://www.mozilla.org/MPL/2.0/FAQ.html for additional information;
- You have to publish any modified unit (e.g. {\f1\fs20 SynTaskDialog.pas}) in a public web site (e.g. {\f1\fs20 http://SoftwareCompany.com/MPL}), with a description of applied modifications, and no removal of the original license header in source code;
-- You make appear some notice available in the program (About box, documentation, online help), stating e.g.\line {\i This software uses some third-party code of the Synopse mORMot framework (C) 2020 Arnaud Bouchez - {\f1\fs20 https://synopse.info} - under Mozilla Public License 1.1; modified source code is available at {\f1\fs20 http://SoftwareCompany.com/MPL}.}
+- You make appear some notice available in the program (About box, documentation, online help), stating e.g.\line {\i This software uses some third-party code of the Synopse mORMot framework (C) 2022 Arnaud Bouchez - {\f1\fs20 https://synopse.info} - under Mozilla Public License 1.1; modified source code is available at {\f1\fs20 http://SoftwareCompany.com/MPL}.}
: Derivate Open Source works
If you want to include part of the framework source code in your own open-source project, you may publish it with a comment similar to this one (as included in the great {\i DelphiWebScript} project by Eric Grange - @http://code.google.com/p/dwscript ):
${
@@ -18478,7 +18493,7 @@ $
$ Sample based on official mORMot's sample
$ "SQLite3\Samples\09 - HttpApi web server\HttpApiServer.dpr"
$
-$ Synopse mORMot framework. Copyright (C) 2020 Arnaud Bouchez
+$ Synopse mORMot framework. Copyright (C) 2022 Arnaud Bouchez
$ Synopse Informatique - https://synopse.info
$
$ Original tri-license: MPL 1.1/GPL 2.0/LGPL 2.1
diff --git a/contrib/mORMot/SQLite3/Samples/11 - Exception logging/LogViewMain.lfm b/contrib/mORMot/SQLite3/Samples/11 - Exception logging/LogViewMain.lfm
index 77b5835..f7fb22a 100644
--- a/contrib/mORMot/SQLite3/Samples/11 - Exception logging/LogViewMain.lfm
+++ b/contrib/mORMot/SQLite3/Samples/11 - Exception logging/LogViewMain.lfm
@@ -14,51 +14,42 @@ object MainLogView: TMainLogView
OnCreate = FormCreate
OnKeyDown = FormKeyDown
OnShow = FormShow
- LCLVersion = '2.0.8.0'
- object Splitter2: TSplitter
- Cursor = crVSplit
- Left = 0
- Height = 4
- Top = 635
- Width = 860
- Align = alBottom
- ResizeAnchor = akBottom
- end
+ LCLVersion = '2.0.11.0'
object Splitter3: TSplitter
Left = 837
- Height = 635
+ Height = 583
Top = 0
Width = 4
Visible = False
end
object Splitter1: TSplitter
Left = 829
- Height = 635
+ Height = 583
Top = 0
Width = 4
Visible = False
end
object Splitter4: TSplitter
Left = 833
- Height = 635
+ Height = 583
Top = 0
Width = 4
Visible = False
end
object PanelLeft: TPanel
Left = 257
- Height = 635
+ Height = 583
Top = 0
Width = 150
Align = alLeft
- ClientHeight = 635
+ ClientHeight = 583
ClientWidth = 150
Constraints.MinWidth = 150
TabOrder = 0
object ImageLogo: TImage
Left = 8
Height = 32
- Top = 591
+ Top = 539
Width = 137
Anchors = [akLeft, akRight, akBottom]
Center = True
@@ -421,9 +412,27 @@ object MainLogView: TMainLogView
TopIndex = -1
end
end
+ object Splitter2: TSplitter
+ Cursor = crVSplit
+ Left = 0
+ Height = 4
+ Top = 583
+ Width = 860
+ Align = alBottom
+ ResizeAnchor = akBottom
+ end
+ object PanelBottom: TPanel
+ Left = 0
+ Height = 52
+ Top = 587
+ Width = 860
+ Align = alBottom
+ TabOrder = 9
+ OnResize = PanelBottomResize
+ end
object List: TDrawGrid
Left = 841
- Height = 635
+ Height = 583
Top = 0
Width = 19
Align = alClient
@@ -447,7 +456,7 @@ object MainLogView: TMainLogView
end
object ProfileList: TDrawGrid
Left = 407
- Height = 635
+ Height = 583
Top = 0
Width = 274
Align = alLeft
@@ -468,17 +477,17 @@ object MainLogView: TMainLogView
end
object PanelThread: TPanel
Left = 681
- Height = 635
+ Height = 583
Top = 0
Width = 148
Align = alLeft
- ClientHeight = 635
+ ClientHeight = 583
ClientWidth = 148
TabOrder = 3
Visible = False
object ThreadListBox: TCheckListBox
Left = 1
- Height = 593
+ Height = 541
Top = 1
Width = 146
Align = alClient
@@ -492,7 +501,7 @@ object MainLogView: TMainLogView
object pnlThreadBottom: TPanel
Left = 1
Height = 40
- Top = 594
+ Top = 542
Width = 146
Align = alBottom
ClientHeight = 40
@@ -512,11 +521,11 @@ object MainLogView: TMainLogView
end
object PanelBrowse: TPanel
Left = 0
- Height = 635
+ Height = 583
Top = 0
Width = 257
Align = alLeft
- ClientHeight = 635
+ ClientHeight = 583
ClientWidth = 257
Constraints.MinWidth = 80
TabOrder = 4
diff --git a/contrib/mORMot/SQLite3/Samples/24 - MongoDB/MongoDBTestCases.pas b/contrib/mORMot/SQLite3/Samples/24 - MongoDB/MongoDBTestCases.pas
index 8c425c6..a5fc2c7 100644
--- a/contrib/mORMot/SQLite3/Samples/24 - MongoDB/MongoDBTestCases.pas
+++ b/contrib/mORMot/SQLite3/Samples/24 - MongoDB/MongoDBTestCases.pas
@@ -57,6 +57,7 @@ type
fInts: TIntegerDynArray;
fCreateTime: TCreateTime;
fData: TSQLRawBlob;
+ fFP: double;
published
property Name: RawUTF8 read fName write fName stored AS_UNIQUE;
property Age: integer read fAge write fAge;
@@ -65,6 +66,7 @@ type
property Ints: TIntegerDynArray index 1 read fInts write fInts;
property Data: TSQLRawBlob read fData write fData;
property CreateTime: TCreateTime read fCreateTime write fCreateTime;
+ property FP: double read fFP write fFP;
end;
TTestORM = class(TSynTestCase)
@@ -183,8 +185,9 @@ begin
Check(serverTime<>0);
CheckSame(Now,serverTime,0.5);
if System.Pos('MongoDB',Owner.CustomVersions)=0 then
- Owner.CustomVersions := Owner.CustomVersions+'Using '+
- string(fClient.ServerBuildInfoText);
+ Owner.CustomVersions := format('%sUsing %s'#13#10'Running on %s'#13#10+
+ 'Compiled with mORMot '+SYNOPSE_FRAMEWORK_VERSION,
+ [Owner.CustomVersions,fClient.ServerBuildInfoText,OSVersionText]);
fExpectedCount := COLL_COUNT;
end;
@@ -452,6 +455,7 @@ begin
R.Value := _ObjFast(['num',i]);
R.Ints := nil;
R.DynArray(1).Add(i);
+ R.FP := i*7.3445;
Check(fClient.BatchAdd(R,True)>=0);
end;
finally
@@ -473,6 +477,7 @@ begin
Check(Length(R.Ints)=1);
Check(R.Ints[0]=aID);
Check(R.CreateTime>=fStartTimeStamp);
+ CheckSame(R.FP,aID*7.3445);
end;
procedure TTestORM.Retrieve;
diff --git a/contrib/mORMot/SQLite3/Samples/30 - MVC Server/MVCModel.pas b/contrib/mORMot/SQLite3/Samples/30 - MVC Server/MVCModel.pas
index ca5b357..57cc4a1 100644
--- a/contrib/mORMot/SQLite3/Samples/30 - MVC Server/MVCModel.pas
+++ b/contrib/mORMot/SQLite3/Samples/30 - MVC Server/MVCModel.pas
@@ -19,12 +19,14 @@ type
fTitle: RawUTF8;
fLanguage: RawUTF8;
fAbout: RawUTF8;
+ fLink: RawUTF8;
published
property Title: RawUTF8 index 80 read fTitle write fTitle;
property Language: RawUTF8 index 3 read fLanguage write fLanguage;
property Description: RawUTF8 index 120 read fDescription write fDescription;
property Copyright: RawUTF8 index 80 read fCopyright write fCopyright;
property About: RawUTF8 read fAbout write fAbout;
+ property Link: RawUTF8 index 60 read fLink write fLink;
end;
TSQLRecordTimeStamped = class(TSQLRecord)
@@ -46,6 +48,7 @@ type
fHashedPassword: RawUTF8;
fLogonName: RawUTF8;
public
+ function ComputeHash(const PlainPassword: RawUTF8): RawUTF8; virtual;
procedure SetPlainPassword(const PlainPassword: RawUTF8);
function CheckPlainPassword(const PlainPassword: RawUTF8): boolean;
function Name: RawUTF8;
@@ -96,6 +99,7 @@ type
OrderID: TIntegerDynArray;
procedure Init(aRest: TSQLRest);
function Get(tagID: integer): RawUTF8;
+ function GetIDFromIdent(const Ident: RawUTF8): integer;
procedure SaveOccurence(aRest: TSQLRest);
procedure SortTagsByIdent(var Tags: TIntegerDynArray);
function GetAsDocVariantArray: Variant;
@@ -106,6 +110,7 @@ type
fAbstract: RawUTF8;
fPublishedMonth: Integer;
fTags: TIntegerDynArray;
+ fLegacyHash: Int64;
public
class function CurrentPublishedMonth: Integer;
class procedure InitializeTable(Server: TSQLRestServer; const FieldName: RawUTF8;
@@ -118,6 +123,8 @@ type
property Abstract: RawUTF8 read fAbstract write fAbstract;
// "index 1" below to allow writing e.g. aArticle.DynArray(1).Delete(aIndex)
property Tags: TIntegerDynArray index 1 read fTags write fTags;
+ // xxhash32 of legacy post_url
+ property LegacyHash: Int64 read fLegacyHash write fLegacyHash;
end;
TSQLArticleSearch = class(TSQLRecordFTS4Porter)
@@ -157,6 +164,8 @@ procedure DotClearFlatImport(Rest: TSQLRest; const aFlatFile: RawUTF8;
var aTagsLookup: TSQLTags; const aDotClearRoot: RawUTF8;
const aStaticFolder: TFileName);
+function ComputeLegacyHash(url: PUTF8Char): cardinal;
+
implementation
@@ -176,12 +185,16 @@ end;
{ TSQLSomeone }
-const
- SALT = 'mORMot';
+function TSQLSomeone.ComputeHash(const PlainPassword: RawUTF8): RawUTF8;
+var dig: THash256;
+begin
+ PBKDF2_SHA3(SHA3_224,PlainPassword,LogonName+'@mORMot',30,@dig);
+ BinToHexLower(@dig,28,result);
+end;
function TSQLSomeone.CheckPlainPassword(const PlainPassword: RawUTF8): boolean;
begin
- result := fHashedPassword=SHA256(SALT+LogonName+PlainPassword);
+ result := fHashedPassword=ComputeHash(PlainPassword);
end;
function TSQLSomeone.Name: RawUTF8;
@@ -191,7 +204,7 @@ end;
procedure TSQLSomeone.SetPlainPassword(const PlainPassword: RawUTF8);
begin
- fHashedPassword := SHA256(SALT+LogonName+PlainPassword);
+ fHashedPassword := ComputeHash(PlainPassword);
end;
@@ -233,6 +246,8 @@ begin
inherited;
if (FieldName='') or (FieldName='PublishedMonth') then
Server.CreateSQLIndex(TSQLArticle,'PublishedMonth',false);
+ if (FieldName='') or (FieldName='LegacyHash') then
+ Server.CreateSQLIndex(TSQLArticle,'LegacyHash',false);
end;
procedure TSQLArticle.SetPublishedMonth(FromTime: TTimeLog);
@@ -260,8 +275,20 @@ begin
result := '';
end;
+function TSQLTags.GetIDFromIdent(const Ident: RawUTF8): integer;
+var i: PtrInt;
+begin
+ if Ident<>'' then
+ for i := 0 to length(Lookup)-1 do
+ if IdemPropNameU(Lookup[i].Ident,Ident) then begin
+ result := i+1;
+ exit;
+ end;
+ result := 0;
+end;
+
function TSQLTags.GetAsDocVariantArray: Variant;
-var i,ndx: Integer;
+var i,ndx: PtrInt;
begin
TDocVariant.NewFast(result);
with Lock.ProtectMethod do
@@ -438,21 +465,46 @@ begin
until P=nil;
end;
+function HttpGet(const aURI: SockString; outHeaders: PSockString=nil;
+ forceNotSocket: boolean=false; outStatus: PInteger=nil): SockString;
+begin
+ result := '';
+ if outStatus<>nil then
+ outStatus^ := 404;
+end;
+
+function ComputeLegacyHash(url: PUTF8Char): cardinal;
+var c: ansichar;
+begin
+ result := 0;
+ if url<>nil then
+ repeat
+ case url^ of
+ #0: exit;
+ 'a'..'z', 'A'..'Z', '0'..'9': begin
+ c := upcase(url^);
+ result := crc32c(result, @c, 1);
+ end;
+ end;
+ inc(url);
+ until false;
+end;
+
procedure DotClearFlatImport(Rest: TSQLRest; const aFlatFile: RawUTF8;
var aTagsLookup: TSQLTags; const aDotClearRoot: RawUTF8;
const aStaticFolder: TFileName);
var T,tagTable,postTable: TDotClearTable;
- data,urls: TRawUTF8List;
+ data: TRawUTF8List;
+ urls: TIntegerDynArray;
info: TSQLBlogInfo;
article: TSQLArticle;
comment: TSQLComment;
tag: TSQLTag;
- tags: TRawUTF8DynArray;
+ tags, notfound: TRawUTF8DynArray;
tagID: TIDDynArray;
tagsCount: integer;
batch: TSQLRestBatch;
PublicFolder: TFileName;
- notfound: TRawUTF8DynArray;
r,ndx,post_url,meta_id,meta_type,tag_post_id,postID,post_id: integer;
function FixLinks(P: PUTF8Char): RawUTF8;
@@ -501,13 +553,20 @@ var T,tagTable,postTable: TDotClearTable;
continue;
AddNoJSONEscape(B,H-B);
P := H;
+ if IdemPChar(P,'HTTP://BLOG.SYNOPSE.INFO/') then
+ inc(P,24)
+ else if IdemPChar(P,'HTTPS://BLOG.SYNOPSE.INFO/') then
+ inc(P,25);
if IdemPChar(P,'HTTP://SYNOPSE.INFO') then begin
AddShort('https://synopse.info');
inc(P,19);
end else if P^='/' then begin
+ if P[1]='?' then
+ inc(P);
if IdemPChar(P+1,'POST/') then begin
GetUrl(P+6);
- i := urls.IndexOf(urlnoparam);
+ i := IntegerScanIndex(pointer(urls),length(urls),
+ ComputeLegacyHash(pointer(urlnoparam)));
if i>=0 then begin
AddShort('articleView?id=');
Add(i+1);
@@ -582,7 +641,6 @@ begin
end;
auto1 := TAutoFree.Several([
@data,TDotClearTable.Parse(aFlatFile),
- @urls,TRawUTF8ListHashed.Create,
@batch,TSQLRestBatch.Create(Rest,TSQLTag,5000)]);
auto2 := TSQLRecord.AutoFree([ // avoid several try..finally
@info,TSQLBlogInfo, @article,TSQLArticle, @comment,TSQLComment, @tag,TSQLTag]);
@@ -614,7 +672,7 @@ begin
post_url := postTable.FieldIndexExisting('post_url');
if postTable.Step(true) then
repeat
- urls.Add(postTable.FieldBuffer(post_url));
+ AddInteger(urls,ComputeLegacyHash(postTable.FieldBuffer(post_url)));
until not postTable.Step;
article.Author := TSQLAuthor(1);
article.AuthorName := 'synopse';
@@ -631,6 +689,7 @@ begin
article.ModifiedAt := Iso8601ToTimeLog(postTable.GetU(r,'post_upddt'));
article.SetPublishedMonth(article.CreatedAt);
postID := postTable.GetAsInteger(r,post_id);
+ article.LegacyHash := ComputeLegacyHash(postTable.Get(r,post_url));
article.Tags := nil;
if tagTable.Step(true) then
repeat
diff --git a/contrib/mORMot/SQLite3/Samples/30 - MVC Server/MVCServer.dpr b/contrib/mORMot/SQLite3/Samples/30 - MVC Server/MVCServer.dpr
index 9262703..bc05d6f 100644
--- a/contrib/mORMot/SQLite3/Samples/30 - MVC Server/MVCServer.dpr
+++ b/contrib/mORMot/SQLite3/Samples/30 - MVC Server/MVCServer.dpr
@@ -38,17 +38,25 @@ var aModel: TSQLModel;
aApplication: TBlogApplication;
aHTTPServer: TSQLHttpServer;
begin
- //with TSQLLog.Family do Level := LOG_VERBOSE;
+ with TSQLLog.Family do begin
+ Level := LOG_VERBOSE;
+ PerThreadLog := ptIdentifiedInOnFile;
+ RotateFileCount := 10;
+ RotateFileSizeKB := 20 shl 10;
+ FileExistsAction := acAppend; // as expected by rotation
+ end;
aModel := CreateModel;
try
aServer := TSQLRestServerDB.Create(aModel,ChangeFileExt(ExeVersion.ProgramFileName,'.db'));
try
aServer.DB.Synchronous := smNormal;
aServer.DB.LockingMode := lmExclusive;
+ aServer.Options := aServer.Options+[rsoNoTableURI];
aServer.CreateMissingTables;
aApplication := TBlogApplication.Create;
try
aApplication.Start(aServer);
+ aServer.ServiceMethodRegisterPublishedMethods('', aApplication);
aHTTPServer := TSQLHttpServer.Create('8092',aServer
{$ifndef ONLYUSEHTTPSOCKET},'+',useHttpApiRegisteringURI{$endif});
try
diff --git a/contrib/mORMot/SQLite3/Samples/30 - MVC Server/MVCViewModel.pas b/contrib/mORMot/SQLite3/Samples/30 - MVC Server/MVCViewModel.pas
index 9b04a97..dfc2678 100644
--- a/contrib/mORMot/SQLite3/Samples/30 - MVC Server/MVCViewModel.pas
+++ b/contrib/mORMot/SQLite3/Samples/30 - MVC Server/MVCViewModel.pas
@@ -12,6 +12,7 @@ uses
SynCommons,
SynLog,
SynTests,
+ SynCrtSock,
mORMot,
mORMotMVC,
MVCModel;
@@ -31,8 +32,9 @@ type
out Comments: TObjectList);
procedure AuthorView(
var ID: TID; out Author: TSQLAuthor; out Articles: variant);
- function Login(
- const LogonName,PlainPassword: RawUTF8): TMVCAction;
+ procedure LoginView;
+ function Login(const LogonName,PlainPassword,
+ NewPlainPassword1,NewPlainPassword2: RawUTF8): TMVCAction;
function Logout: TMVCAction;
function ArticleComment(ID: TID; const Title,Comment: RawUTF8): TMVCAction;
function ArticleMatch(const Match: RawUTF8): TMVCAction;
@@ -71,7 +73,13 @@ type
procedure TagToText(const Value: variant; out result: variant);
public
procedure Start(aServer: TSQLRestServer); reintroduce;
+ published
+ // low-level blog/post blog/tag blog/rss endpoints
+ procedure Post(Ctxt: TSQLRestServerURIContext);
+ procedure Tag(Ctxt: TSQLRestServerURIContext);
+ procedure Rss(Ctxt: TSQLRestServerURIContext);
public
+ // IBlogApplication implemented methods
procedure Default(var Scope: variant);
procedure ArticleView(ID: TID;
var WithComments: boolean; Direction: integer; var Scope: variant;
@@ -79,7 +87,9 @@ type
out Comments: TObjectList);
procedure AuthorView(
var ID: TID; out Author: TSQLAuthor; out Articles: variant);
- function Login(const LogonName,PlainPassword: RawUTF8): TMVCAction;
+ procedure LoginView;
+ function Login(const LogonName,PlainPassword,
+ NewPlainPassword1,NewPlainPassword2: RawUTF8): TMVCAction;
function Logout: TMVCAction;
function ArticleComment(ID: TID; const Title,Comment: RawUTF8): TMVCAction;
function ArticleMatch(const Match: RawUTF8): TMVCAction;
@@ -130,6 +140,10 @@ begin
finally
Free;
end;
+ _Safe(fBlogMainInfo)^.AddValue('engine',RawUTF8ToVariant(
+ 'Website powered by mORMot MVC '+SYNOPSE_FRAMEWORK_VERSION+
+ ', compiled with '+GetDelphiCompilerVersion+
+ ', running on '+RawUTF8(ToText(OSVersion32))+'.'));
end;
procedure TBlogApplication.MonthToText(const Value: variant;
@@ -172,29 +186,28 @@ begin
auto := TSQLRecord.AutoFree([ // avoid several try..finally
@info,TSQLBlogInfo, @article,TSQLArticle, @comment,TSQLComment, @tag,TSQLTag]);
if not RestModel.Retrieve('',info) then begin // retrieve first item
- tmp := StringFromFile('/home/ab/Downloads/2020-06-16-a8003957c2ae6bde5be6ea279c9c9ce4-backup.txt');
+ tmp := StringFromFile(ExeVersion.ProgramFilePath+'2021-01-20-16-37-default-backup.txt');
info.Language := 'en';
if tmp<>'' then begin
info.Title := 'Synopse Blog';
info.Description := 'Articles, announcements, news, updates and more '+
- 'about our Open Source projects';
+ 'about Synopse Open Source projects';
info.About := 'Latest information about Synopse Open Source librairies, '+
'mainly the mORMot ORM/SOA/MVC framework, and SynPDF.';
+ info.Link := 'https://blog.synopse.info';
end else begin
info.Title := 'mORMot BLOG';
info.Description := 'Sample Blog Web Application using Synopse mORMot MVC';
info.About := TSynTestCase.RandomTextParagraph(10,'!');
+ info.Link := 'http://localhost:8092';
end;
- info.About := info.About+#13#10'Website powered by mORMot MVC '+
- SYNOPSE_FRAMEWORK_VERSION+', compiled with '+GetDelphiCompilerVersion+
- ', running on '+ToText(OSVersion32)+'.';
info.Copyright := '©'+ToUTF8(CurrentYear)+'Synopse Informatique';
RestModel.Add(info,true);
end;
if RestModel.TableHasRows(TSQLArticle) then
exit;
if tmp<>'' then begin
- DotClearFlatImport(RestModel,tmp,fTagsLookup,'http://blog.synopse.info',
+ DotClearFlatImport(RestModel,tmp,fTagsLookup,'https://blog.synopse.info',
(TMVCRunOnRestServer(fMainRunner).Views as TMVCViewsMustache).ViewStaticFolder);
exit;
end;
@@ -271,20 +284,24 @@ begin
fDefaultData.AddNewProp('tags',fTagsLookup.GetAsDocVariantArray,info);
end;
-procedure TBlogApplication.FlushAnyCache;
-begin
- inherited FlushAnyCache; // call fMainRunner.NotifyContentChanged
- fDefaultData.Clear;
-end;
-
-
-{ TBlogApplication - Commands }
-
const
ARTICLE_FIELDS = 'RowID,Title,Tags,Abstract,ContentHtml,Author,AuthorName,CreatedAt';
ARTICLE_DEFAULT_LIMIT = ' limit 20';
ARTICLE_DEFAULT_ORDER: RawUTF8 = 'order by RowID desc'+ARTICLE_DEFAULT_LIMIT;
+procedure TBlogApplication.FlushAnyCache;
+begin
+ inherited FlushAnyCache; // call fMainRunner.NotifyContentChanged
+ fDefaultData.Clear;
+ // get last 20 articles
+ fDefaultData.SetValue('Articles',
+ RestModel.RetrieveDocVariantArray(TSQLArticle,'',
+ ARTICLE_DEFAULT_ORDER,[],ARTICLE_FIELDS,nil,@fDefaultLastID));
+end;
+
+
+{ TBlogApplication - Commands }
+
procedure TBlogApplication.Default(var Scope: variant);
var scop: PDocVariantData;
lastID: TID;
@@ -320,14 +337,12 @@ begin
whereClause := whereClause+' and IntegerDynArrayContains(Tags,?)';
end;
SetVariantNull(Scope);
- if (lastID=0) and (tag=0) then begin // use simple cache if no parameters
- if not fDefaultData.AddExistingProp('Articles',Scope) then begin
- articles := RestModel.RetrieveDocVariantArray(TSQLArticle,'',
- ARTICLE_DEFAULT_ORDER,[],ARTICLE_FIELDS,nil,@fDefaultLastID);
- fDefaultData.AddNewProp('Articles',articles,Scope);
- end;
+ if (lastID=0) and (tag=0) then begin
+ // use simple cache if no parameters
+ fDefaultData.AddExistingProp('Articles',Scope); // set by FlushAnyCache
lastID := fDefaultLastID;
- end else begin // use more complex request using lastID + tag parameters
+ end else begin
+ // use more complex request using lastID + tag parameters
articles := RestModel.RetrieveDocVariantArray(TSQLArticle,'',
whereClause+ARTICLE_DEFAULT_ORDER,[lastID,tag],ARTICLE_FIELDS,nil,@lastID);
scope := _ObjFast(['Articles',articles]);
@@ -370,12 +385,31 @@ begin
raise EMVCApplication.CreateGotoError(HTTP_NOTFOUND);
end;
-function TBlogApplication.Login(const LogonName, PlainPassword: RawUTF8): TMVCAction;
+procedure TBlogApplication.LoginView;
+begin
+end;
+
+function TBlogApplication.Login(const LogonName, PlainPassword,
+ NewPlainPassword1, NewPlainPassword2: RawUTF8): TMVCAction;
var Author: TSQLAuthor;
SessionInfo: TCookieData;
+ newpwd: RawUTF8;
begin
- if CurrentSession.CheckAndRetrieve<>0 then begin
- GotoError(result,HTTP_BADREQUEST);
+ if LogonName='' then begin
+ GotoView(result,'LoginView',[]);
+ exit;
+ end;
+ newpwd := Trim(NewPlainPassword1);
+ if newpwd<>'' then begin
+ if (newpwd<>NewPlainPassword2) or
+ (newpwd=PlainPassword) or
+ (CurrentSession.CheckAndRetrieve(@SessionInfo,TypeInfo(TCookieData))=0) or
+ (SessionInfo.AuthorName<>LogonName) then begin
+ GotoError(result,HTTP_NOTACCEPTABLE);
+ exit;
+ end;
+ end else if CurrentSession.CheckAndRetrieve<>0 then begin
+ GotoError(result,'Already Logged In',HTTP_BADREQUEST);
exit;
end;
Author := TSQLAuthor.Create(RestModel,'LogonName=?',[LogonName]);
@@ -385,6 +419,10 @@ begin
SessionInfo.AuthorID := Author.ID;
SessionInfo.AuthorRights := Author.Rights;
CurrentSession.Initialize(@SessionInfo,TypeInfo(TCookieData));
+ if newpwd<>'' then begin
+ Author.SetPlainPassword(newpwd);
+ RestModel.Update(Author,'HashedPassword');
+ end;
GotoDefault(result);
end else
GotoError(result,sErrorInvalidLogin);
@@ -481,6 +519,83 @@ begin
end;
end;
+procedure TBlogApplication.Post(Ctxt: TSQLRestServerURIContext);
+var hash, id: Int64;
+begin
+ hash := ComputeLegacyHash(pointer(UrlDecode(Ctxt.URIAfterRoot,5,-1)));
+ id := RestModel.OneFieldValueInt64(TSQLArticle,'ID',
+ FormatUTF8('LegacyHash=:(%):', [hash]));
+ Ctxt.Redirect(FormatUTF8('/%/articleview?id=%',[RestModel.Model.Root,id]));
+end;
+
+procedure TBlogApplication.Tag(Ctxt: TSQLRestServerURIContext);
+var
+ id: integer;
+begin
+ id := fTagsLookup.GetIDFromIdent(copy(Ctxt.UriAfterRoot, 5, 100));
+ Ctxt.Redirect(FormatUTF8('/%/default?scope={tag:%}',[RestModel.Model.Root,id]));
+end;
+
+function Esc(const Msg: RawUTF8): RawUTF8;
+var i: integer;
+ ins: RawUTF8;
+begin
+ // fast enough for our purpose to compute some RSS cache
+ result := Msg;
+ for i := length(Msg) downto 1 do begin
+ case Msg[i] of
+ '"': ins := '"';
+ '&': ins := '&';
+ '<': ins := '<';
+ '>': ins := '>';
+ else Continue;
+ end;
+ result[i] := ';';
+ insert(ins,result,i);
+ end;
+end;
+
+procedure TBlogApplication.Rss(Ctxt: TSQLRestServerURIContext);
+ function ComputeRss: variant;
+ var xml, lng, link: RawUTF8;
+ art: integer;
+ begin
+ with _Safe(fBlogMainInfo)^ do
+ begin
+ link := U['Link'];
+ if (link<>'') and (link[length(link)]='/') then
+ SetLength(link,length(link)-1);
+ lng := U['Language'];
+ if lng='' then
+ lng := 'en_US';
+ FormatUTF8('
--{{Title}}
-{{#ContentHtml}}{{{Content}}}{{/ContentHtml}}{{^ContentHtml}}{{{WikiToHtml Content}}}{{/ContentHtml}}
-
No comment yet.{{/Comments}} - - {{#main.session.AuthorRights.Comment}} - - - {{/main.session.AuthorRights.Comment}} - - {{/WithComments}} - {{^WithComments}} - - {{/WithComments}} +
++{{Title}}
+{{#ContentHtml}}{{{Content}}}{{/ContentHtml}}{{^ContentHtml}}{{{WikiToHtml Content}}}{{/ContentHtml}}
+Commented on {{TimeLogToText CreatedAt}} by {{AuthorName}} +
No comment yet.{{/Comments}} + + {{#main.session.AuthorRights.Comment}} + + + {{/main.session.AuthorRights.Comment}} + + {{/WithComments}} + {{^WithComments}} + + {{/WithComments}} {{>footer}} \ No newline at end of file diff --git a/contrib/mORMot/SQLite3/Samples/30 - MVC Server/Views/AuthorView.html b/contrib/mORMot/SQLite3/Samples/30 - MVC Server/Views/AuthorView.html index 0b0dca9..2f8dfee 100644 --- a/contrib/mORMot/SQLite3/Samples/30 - MVC Server/Views/AuthorView.html +++ b/contrib/mORMot/SQLite3/Samples/30 - MVC Server/Views/AuthorView.html @@ -1,15 +1,25 @@ {{>header}} {{>masthead}} -