{**************************************************************************************************} { } { Project JEDI Code Library (JCL) } { } { The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); } { you may not use this file except in compliance with the License. You may obtain a copy of the } { License at http://www.mozilla.org/MPL/ } { } { Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF } { ANY KIND, either express or implied. See the License for the specific language governing rights } { and limitations under the License. } { } { The Original Code is JclBase.pas. } { } { The Initial Developer of the Original Code is Marcel van Brakel. } { Portions created by Marcel van Brakel are Copyright Marcel van Brakel. All rights reserved. } { } { Contributors: } { Marcel van Brakel, } { Peter Friese, } { Robert Marquardt (marquardt) } { Robert Rossmair (rrossmair) } { Petr Vones (pvones) } { Florent Ouchet (outchy) } { } {**************************************************************************************************} { } { This unit contains generic JCL base classes and routines to support earlier } { versions of Delphi as well as FPC. } { } {**************************************************************************************************} { } { Last modified: $Date:: 2009-01-21 10:13:02 +0100 (mer., 21 janv. 2009) $ } { Revision: $Rev:: 2604 $ } { Author: $Author:: outchy $ } { } {**************************************************************************************************} unit JclBase; {$I jcl.inc} interface uses {$IFDEF UNITVERSIONING} JclUnitVersioning, {$ENDIF UNITVERSIONING} {$IFDEF CLR} Classes, System.Reflection, {$ELSE} {$IFDEF MSWINDOWS} Windows, {$ENDIF MSWINDOWS} {$ENDIF CLR} {$IFDEF SUPPORTS_GENERICS} {$IFDEF CLR} System.Collections.Generic, {$ENDIF CLR} {$ENDIF SUPPORTS_GENERICS} SysUtils; // Version const JclVersionMajor = 1; // 0=pre-release|beta/1, 2, ...=final JclVersionMinor = 104; // Fifth minor release since JCL 1.90 JclVersionRelease = 1; // 0: pre-release|beta/ 1: release JclVersionBuild = 3248; // build number, days since march 1, 2000 JclVersion = (JclVersionMajor shl 24) or (JclVersionMinor shl 16) or (JclVersionRelease shl 15) or (JclVersionBuild shl 0); // EJclError type EJclError = class(Exception); {$IFDEF CLR} DWORD = LongWord; TIntegerSet = set of 0..SizeOf(Integer) * 8 - 1; {$ENDIF CLR} // EJclWin32Error {$IFDEF MSWINDOWS} type EJclWin32Error = class(EJclError) private FLastError: DWORD; FLastErrorMsg: string; public constructor Create(const Msg: string); constructor CreateFmt(const Msg: string; const Args: array of const); {$IFNDEF CLR} constructor CreateRes(Ident: Integer); overload; constructor CreateRes(ResStringRec: PResStringRec); overload; {$ENDIF ~CLR} property LastError: DWORD read FLastError; property LastErrorMsg: string read FLastErrorMsg; end; {$ENDIF MSWINDOWS} // EJclInternalError type EJclInternalError = class(EJclError); // Types type {$IFDEF MATH_EXTENDED_PRECISION} Float = Extended; {$ENDIF MATH_EXTENDED_PRECISION} {$IFDEF MATH_DOUBLE_PRECISION} Float = Double; {$ENDIF MATH_DOUBLE_PRECISION} {$IFDEF MATH_SINGLE_PRECISION} Float = Single; {$ENDIF MATH_SINGLE_PRECISION} PFloat = ^Float; type {$IFDEF FPC} Largeint = Int64; {$ELSE} PPointer = ^Pointer; {$IFDEF RTL140_UP} {$IFDEF CLR} PJclByteArray = TBytes; {$ELSE} PByte = System.PByte; Int8 = ShortInt; Int16 = Smallint; Int32 = Integer; UInt8 = Byte; UInt16 = Word; UInt32 = LongWord; {$ENDIF CLR} {$ELSE ~RTL140_UP} PBoolean = ^Boolean; PByte = Windows.PByte; {$ENDIF ~RTL140_UP} {$ENDIF FPC} PCardinal = ^Cardinal; {$IFNDEF COMPILER7_UP} UInt64 = Int64; {$ENDIF ~COMPILER7_UP} {$IFNDEF CLR} PWideChar = System.PWideChar; PPWideChar = ^JclBase.PWideChar; PInt64 = type System.PInt64; PPInt64 = ^JclBase.PInt64; {$ENDIF CLR} // Interface compatibility {$IFDEF SUPPORTS_INTERFACE} {$IFNDEF FPC} {$IFNDEF RTL140_UP} type IInterface = IUnknown; {$ENDIF ~RTL140_UP} {$ENDIF ~FPC} {$ENDIF SUPPORTS_INTERFACE} // Int64 support procedure I64ToCardinals(I: Int64; var LowPart, HighPart: Cardinal); procedure CardinalsToI64(var I: Int64; const LowPart, HighPart: Cardinal); // Redefinition of TLargeInteger to relieve dependency on Windows.pas type PLargeInteger = ^TLargeInteger; TLargeInteger = Int64; {$IFNDEF COMPILER11_UP} TBytes = array of Byte; {$ENDIF ~COMPILER11_UP} {$IFDEF CLR} type TJclBytes = TBytes; {$ELSE} // Redefinition of PByteArray to avoid range check exceptions. type TJclByteArray = array [0..MaxInt div SizeOf(Byte) - 1] of Byte; PJclByteArray = ^TJclByteArray; TJclBytes = Pointer; // under .NET System.pas: TBytes = array of Byte; // Redefinition of TULargeInteger to relieve dependency on Windows.pas type PULargeInteger = ^TULargeInteger; TULargeInteger = record case Integer of 0: (LowPart: LongWord; HighPart: LongWord); 1: (QuadPart: Int64); end; {$ENDIF ~CLR} // Dynamic Array support type TDynByteArray = array of Byte; TDynShortIntArray = array of Shortint; TDynWordArray = array of Word; TDynSmallIntArray = array of Smallint; TDynLongIntArray = array of Longint; TDynInt64Array = array of Int64; TDynCardinalArray = array of Cardinal; TDynIntegerArray = array of Integer; TDynExtendedArray = array of Extended; TDynDoubleArray = array of Double; TDynSingleArray = array of Single; TDynFloatArray = array of Float; {$IFNDEF CLR} TDynPointerArray = array of Pointer; {$ENDIF ~CLR} TDynStringArray = array of string; TDynAnsiStringArray = array of AnsiString; TDynWideStringArray = array of WideString; {$IFDEF SUPPORTS_UNICODE_STRING} TDynUnicodeStringArray = array of UnicodeString; {$ENDIF SUPPORTS_UNICODE_STRING} TDynIInterfaceArray = array of IInterface; TDynObjectArray = array of TObject; TDynCharArray = array of Char; TDynAnsiCharArray = array of AnsiChar; TDynWideCharArray = array of WideChar; // Cross-Platform Compatibility const // line delimiters for a version of Delphi/C++Builder NativeLineFeed = Char(#10); NativeCarriageReturn = Char(#13); NativeCrLf = string(#13#10); // default line break for a version of Delphi on a platform {$IFDEF MSWINDOWS} NativeLineBreak = NativeCrLf; {$ENDIF MSWINDOWS} {$IFDEF UNIX} NativeLineBreak = NativeLineFeed; {$ENDIF UNIX} HexPrefixPascal = string('$'); HexPrefixC = string('0x'); {$IFDEF BCB} HexPrefix = HexPrefixC; {$ELSE ~BCB} HexPrefix = HexPrefixPascal; {$ENDIF ~BCB} const BOM_UTF16_LSB: array [0..1] of Byte = ($FF,$FE); BOM_UTF16_MSB: array [0..1] of Byte = ($FE,$FF); BOM_UTF8: array [0..2] of Byte = ($EF,$BB,$BF); BOM_UTF32_LSB: array [0..3] of Byte = ($FF,$FE,$00,$00); BOM_UTF32_MSB: array [0..3] of Byte = ($00,$00,$FE,$FF); // BOM_UTF7_1: array [0..3] of Byte = ($2B,$2F,$76,$38); // BOM_UTF7_2: array [0..3] of Byte = ($2B,$2F,$76,$39); // BOM_UTF7_3: array [0..3] of Byte = ($2B,$2F,$76,$2B); // BOM_UTF7_4: array [0..3] of Byte = ($2B,$2F,$76,$2F); // BOM_UTF7_5: array [0..3] of Byte = ($2B,$2F,$76,$38,$2D); type // Unicode transformation formats (UTF) data types PUTF7 = ^UTF7; UTF7 = AnsiChar; PUTF8 = ^UTF8; UTF8 = AnsiChar; PUTF16 = ^UTF16; UTF16 = WideChar; PUTF32 = ^UTF32; UTF32 = Cardinal; // UTF conversion schemes (UCS) data types PUCS4 = ^UCS4; UCS4 = Cardinal; PUCS2 = PWideChar; UCS2 = WideChar; TUCS2Array = array of UCS2; TUCS4Array = array of UCS4; // string types TUTF8String = AnsiString; TUTF16String = WideString; TUCS2String = WideString; var AnsiReplacementCharacter: AnsiChar; const UCS4ReplacementCharacter: UCS4 = $0000FFFD; MaximumUCS2: UCS4 = $0000FFFF; MaximumUTF16: UCS4 = $0010FFFF; MaximumUCS4: UCS4 = $7FFFFFFF; SurrogateHighStart = UCS4($D800); SurrogateHighEnd = UCS4($DBFF); SurrogateLowStart = UCS4($DC00); SurrogateLowEnd = UCS4($DFFF); // basic set types type TSetOfAnsiChar = set of AnsiChar; {$IFNDEF XPLATFORM_RTL} procedure RaiseLastOSError; {$ENDIF ~XPLATFORM_RTL} procedure MoveArray(var List: TDynIInterfaceArray; FromIndex, ToIndex, Count: Integer); overload; {$IFNDEF CLR} procedure MoveArray(var List: TDynStringArray; FromIndex, ToIndex, Count: Integer); overload; procedure MoveArray(var List: TDynFloatArray; FromIndex, ToIndex, Count: Integer); overload; procedure MoveArray(var List: TDynPointerArray; FromIndex, ToIndex, Count: Integer); overload; {$IFDEF SUPPORTS_UNICODE_STRING} procedure MoveArray(var List: TDynUnicodeStringArray; FromIndex, ToIndex, Count: Integer); overload; {$ENDIF SUPPORTS_UNICODE_STRING} {$ENDIF ~CLR} {$IFNDEF FPC} procedure MoveArray(var List: TDynAnsiStringArray; FromIndex, ToIndex, Count: Integer); overload; {$ENDIF} procedure MoveArray(var List: TDynWideStringArray; FromIndex, ToIndex, Count: Integer); overload; procedure MoveArray(var List: TDynObjectArray; FromIndex, ToIndex, Count: Integer); overload; procedure MoveArray(var List: TDynSingleArray; FromIndex, ToIndex, Count: Integer); overload; procedure MoveArray(var List: TDynDoubleArray; FromIndex, ToIndex, Count: Integer); overload; {$IFNDEF FPC} procedure MoveArray(var List: TDynExtendedArray; FromIndex, ToIndex, Count: Integer); overload; {$ENDIF} procedure MoveArray(var List: TDynIntegerArray; FromIndex, ToIndex, Count: Integer); overload; procedure MoveArray(var List: TDynCardinalArray; FromIndex, ToIndex, Count: Integer); overload; procedure MoveArray(var List: TDynInt64Array; FromIndex, ToIndex, Count: Integer); overload; procedure MoveChar(const Source: string; FromIndex: Integer; var Dest: string; ToIndex, Count: Integer); overload; // Index: 0..n-1 {$IFDEF CLR} function GetBytesEx(const Value): TBytes; procedure SetBytesEx(var Value; Bytes: TBytes); procedure SetIntegerSet(var DestSet: TIntegerSet; Value: UInt32); inline; function AnsiByteArrayStringLen(Data: TBytes): Integer; function StringToAnsiByteArray(const S: string): TBytes; function AnsiByteArrayToString(const Data: TBytes; Count: Integer): string; type TStringAnsiBufferStreamHelper = class helper for TStream public function WriteStringAnsiBuffer(const Buffer: string): Integer; overload; function WriteStringAnsiBuffer(const Buffer: string; StrLen: Integer): Integer; overload; function ReadStringAnsiBuffer(var Buffer: string; AnsiLen: Integer): Integer; overload; function WriteStringAnsiBuffer(const Buffer: AnsiString): Integer; overload; function WriteStringAnsiBuffer(const Buffer: AnsiString; StrLen: Integer): Integer; overload; function ReadStringAnsiBuffer(var Buffer: AnsiString; AnsiLen: Integer): Integer; overload; end; {$ENDIF CLR} {$IFNDEF CLR} function BytesOf(const Value: AnsiString): TBytes; overload; {$IFDEF COMPILER6_UP} function BytesOf(const Value: WideString): TBytes; overload; function BytesOf(const Value: WideChar): TBytes; overload; {$ENDIF COMPILER6_UP} function BytesOf(const Value: AnsiChar): TBytes; overload; function StringOf(const Bytes: array of Byte): AnsiString; overload; function StringOf(const Bytes: Pointer; Size: Cardinal): AnsiString; overload; {$ENDIF CLR} {$IFNDEF COMPILER11_UP} type // Definitions for 32 Bit Compilers // From BaseTsd.h INT_PTR = Integer; {$EXTERNALSYM INT_PTR} LONG_PTR = Longint; {$EXTERNALSYM LONG_PTR} UINT_PTR = Cardinal; {$EXTERNALSYM UINT_PTR} ULONG_PTR = LongWord; {$EXTERNALSYM ULONG_PTR} DWORD_PTR = ULONG_PTR; {$EXTERNALSYM DWORD_PTR} {$ENDIF COMPILER11_UP} type TJclAddr64 = Int64; TJclAddr32 = Cardinal; {$IFDEF 64BIT} TJclAddr = TJclAddr64; {$ELSE ~64BIT} TJclAddr = TJclAddr32; {$ENDIF} EJclAddr64Exception = class(EJclError); function Addr64ToAddr32(const Value: TJclAddr64): TJclAddr32; function Addr32ToAddr64(const Value: TJclAddr32): TJclAddr64; {$IFDEF SUPPORTS_GENERICS} type TCompare = function(const Obj1, Obj2: T): Integer; TEqualityCompare = function(const Obj1, Obj2: T): Boolean; THashConvert = function(const AItem: T): Integer; {$IFNDEF CLR} IEqualityComparer = interface function Equals(A, B: T): Boolean; function GetHashCode(Obj: T): Integer; end; {$ENDIF CLR} TEquatable = class(TInterfacedObject, IEquatable, IEqualityComparer) public { IEquatable } function TestEquals(Other: T): Boolean; overload; function IEquatable.Equals = TestEquals; { IEqualityComparer } function TestEquals(A, B: T): Boolean; overload; function IEqualityComparer.Equals = TestEquals; function GetHashCode2(Obj: T): Integer; function IEqualityComparer.GetHashCode = GetHashCode2; end; {$ENDIF SUPPORTS_GENERICS} {$IFDEF UNITVERSIONING} const UnitVersioning: TUnitVersionInfo = ( RCSfile: '$URL: https://jcl.svn.sourceforge.net/svnroot/jcl/tags/JCL-1.104-Build3248/jcl/source/common/JclBase.pas $'; Revision: '$Revision: 2604 $'; Date: '$Date: 2009-01-21 10:13:02 +0100 (mer., 21 janv. 2009) $'; LogPath: 'JCL\source\common' ); {$ENDIF UNITVERSIONING} implementation uses JclResources; procedure MoveArray(var List: TDynIInterfaceArray; FromIndex, ToIndex, Count: Integer); overload; {$IFDEF CLR} var I: Integer; begin if FromIndex < ToIndex then begin for I := Count - 1 downto 0 do List[ToIndex + I] := List[FromIndex + I]; if (ToIndex - FromIndex) < Count then // overlapped source and target for I := 0 to ToIndex - FromIndex - 1 do List[FromIndex + I] := nil else // independant for I := 0 to Count - 1 do List[FromIndex + I] := nil; end else if FromIndex > ToIndex then begin for I := 0 to Count - 1 do List[ToIndex + I] := List[FromIndex + I]; if (FromIndex - ToIndex) < Count then // overlapped source and target for I := Count - FromIndex + ToIndex to Count - 1 do List[FromIndex + I] := nil else // independant for I := 0 to Count - 1 do List[FromIndex + I] := nil; end; end; {$ELSE} begin if Count > 0 then begin Move(List[FromIndex], List[ToIndex], Count * SizeOf(List[0])); { Keep reference counting working } if FromIndex < ToIndex then begin if (ToIndex - FromIndex) < Count then FillChar(List[FromIndex], (ToIndex - FromIndex) * SizeOf(List[0]), 0) else FillChar(List[FromIndex], Count * SizeOf(List[0]), 0); end else if FromIndex > ToIndex then begin if (FromIndex - ToIndex) < Count then FillChar(List[ToIndex + Count], (FromIndex - ToIndex) * SizeOf(List[0]), 0) else FillChar(List[FromIndex], Count * SizeOf(List[0]), 0); end; end; end; {$ENDIF CLR} {$IFNDEF CLR} procedure MoveArray(var List: TDynStringArray; FromIndex, ToIndex, Count: Integer); overload; begin if Count > 0 then begin Move(List[FromIndex], List[ToIndex], Count * SizeOf(List[0])); { Keep reference counting working } if FromIndex < ToIndex then begin if (ToIndex - FromIndex) < Count then FillChar(List[FromIndex], (ToIndex - FromIndex) * SizeOf(List[0]), 0) else FillChar(List[FromIndex], Count * SizeOf(List[0]), 0); end else if FromIndex > ToIndex then begin if (FromIndex - ToIndex) < Count then FillChar(List[ToIndex + Count], (FromIndex - ToIndex) * SizeOf(List[0]), 0) else FillChar(List[FromIndex], Count * SizeOf(List[0]), 0); end; end; end; procedure MoveArray(var List: TDynFloatArray; FromIndex, ToIndex, Count: Integer); overload; begin if Count > 0 then begin Move(List[FromIndex], List[ToIndex], Count * SizeOf(List[0])); { Clean array } if FromIndex < ToIndex then begin if (ToIndex - FromIndex) < Count then FillChar(List[FromIndex], (ToIndex - FromIndex) * SizeOf(List[0]), 0) else FillChar(List[FromIndex], Count * SizeOf(List[0]), 0); end else if FromIndex > ToIndex then begin if (FromIndex - ToIndex) < Count then FillChar(List[ToIndex + Count], (FromIndex - ToIndex) * SizeOf(List[0]), 0) else FillChar(List[FromIndex], Count * SizeOf(List[0]), 0); end; end; end; procedure MoveArray(var List: TDynPointerArray; FromIndex, ToIndex, Count: Integer); overload; begin if Count > 0 then begin Move(List[FromIndex], List[ToIndex], Count * SizeOf(List[0])); { Clean array } if FromIndex < ToIndex then begin if (ToIndex - FromIndex) < Count then FillChar(List[FromIndex], (ToIndex - FromIndex) * SizeOf(List[0]), 0) else FillChar(List[FromIndex], Count * SizeOf(List[0]), 0); end else if FromIndex > ToIndex then begin if (FromIndex - ToIndex) < Count then FillChar(List[ToIndex + Count], (FromIndex - ToIndex) * SizeOf(List[0]), 0) else FillChar(List[FromIndex], Count * SizeOf(List[0]), 0); end; end; end; {$IFDEF SUPPORTS_UNICODE_STRING} procedure MoveArray(var List: TDynUnicodeStringArray; FromIndex, ToIndex, Count: Integer); overload; begin if Count > 0 then begin Move(List[FromIndex], List[ToIndex], Count * SizeOf(List[0])); { Keep reference counting working } if FromIndex < ToIndex then begin if (ToIndex - FromIndex) < Count then FillChar(List[FromIndex], (ToIndex - FromIndex) * SizeOf(List[0]), 0) else FillChar(List[FromIndex], Count * SizeOf(List[0]), 0); end else if FromIndex > ToIndex then begin if (FromIndex - ToIndex) < Count then FillChar(List[ToIndex + Count], (FromIndex - ToIndex) * SizeOf(List[0]), 0) else FillChar(List[FromIndex], Count * SizeOf(List[0]), 0); end; end; end; {$ENDIF SUPPORTS_UNICODE_STRING} {$ENDIF ~CLR} {$IFNDEF FPC} procedure MoveArray(var List: TDynAnsiStringArray; FromIndex, ToIndex, Count: Integer); overload; {$IFDEF CLR} var I: Integer; begin if FromIndex < ToIndex then begin for I := Count - 1 downto 0 do List[ToIndex + I] := List[FromIndex + I]; if (ToIndex - FromIndex) < Count then // overlapped source and target for I := 0 to ToIndex - FromIndex - 1 do List[FromIndex + I] := '' else // independant for I := 0 to Count - 1 do List[FromIndex + I] := ''; end else if FromIndex > ToIndex then begin for I := 0 to Count - 1 do List[ToIndex + I] := List[FromIndex + I]; if (FromIndex - ToIndex) < Count then // overlapped source and target for I := Count - FromIndex + ToIndex to Count - 1 do List[FromIndex + I] := '' else // independant for I := 0 to Count - 1 do List[FromIndex + I] := ''; end; end; {$ELSE} begin if Count > 0 then begin Move(List[FromIndex], List[ToIndex], Count * SizeOf(List[0])); { Keep reference counting working } if FromIndex < ToIndex then begin if (ToIndex - FromIndex) < Count then FillChar(List[FromIndex], (ToIndex - FromIndex) * SizeOf(List[0]), 0) else FillChar(List[FromIndex], Count * SizeOf(List[0]), 0); end else if FromIndex > ToIndex then begin if (FromIndex - ToIndex) < Count then FillChar(List[ToIndex + Count], (FromIndex - ToIndex) * SizeOf(List[0]), 0) else FillChar(List[FromIndex], Count * SizeOf(List[0]), 0); end; end; end; {$ENDIF CLR} {$ENDIF FPC} procedure MoveArray(var List: TDynWideStringArray; FromIndex, ToIndex, Count: Integer); overload; {$IFDEF CLR} var I: Integer; begin if FromIndex < ToIndex then begin for I := Count - 1 downto 0 do List[ToIndex + I] := List[FromIndex + I]; if (ToIndex - FromIndex) < Count then // overlapped source and target for I := 0 to ToIndex - FromIndex - 1 do List[FromIndex + I] := '' else // independant for I := 0 to Count - 1 do List[FromIndex + I] := ''; end else if FromIndex > ToIndex then begin for I := 0 to Count - 1 do List[ToIndex + I] := List[FromIndex + I]; if (FromIndex - ToIndex) < Count then // overlapped source and target for I := Count - FromIndex + ToIndex to Count - 1 do List[FromIndex + I] := '' else // independant for I := 0 to Count - 1 do List[FromIndex + I] := ''; end; end; {$ELSE} begin if Count > 0 then begin Move(List[FromIndex], List[ToIndex], Count * SizeOf(List[0])); { Keep reference counting working } if FromIndex < ToIndex then begin if (ToIndex - FromIndex) < Count then FillChar(List[FromIndex], (ToIndex - FromIndex) * SizeOf(List[0]), 0) else FillChar(List[FromIndex], Count * SizeOf(List[0]), 0); end else if FromIndex > ToIndex then begin if (FromIndex - ToIndex) < Count then FillChar(List[ToIndex + Count], (FromIndex - ToIndex) * SizeOf(List[0]), 0) else FillChar(List[FromIndex], Count * SizeOf(List[0]), 0); end; end; end; {$ENDIF CLR} procedure MoveArray(var List: TDynObjectArray; FromIndex, ToIndex, Count: Integer); overload; {$IFDEF CLR} var I: Integer; begin if FromIndex < ToIndex then begin for I := Count - 1 downto 0 do List[ToIndex + I] := List[FromIndex + I]; if (ToIndex - FromIndex) < Count then // overlapped source and target for I := 0 to ToIndex - FromIndex - 1 do List[FromIndex + I] := nil else // independant for I := 0 to Count - 1 do List[FromIndex + I] := nil; end else if FromIndex > ToIndex then begin for I := 0 to Count - 1 do List[ToIndex + I] := List[FromIndex + I]; if (FromIndex - ToIndex) < Count then // overlapped source and target for I := Count - FromIndex + ToIndex to Count - 1 do List[FromIndex + I] := nil else // independant for I := 0 to Count - 1 do List[FromIndex + I] := nil; end; end; {$ELSE} begin if Count > 0 then begin Move(List[FromIndex], List[ToIndex], Count * SizeOf(List[0])); { Clean array } if FromIndex < ToIndex then begin if (ToIndex - FromIndex) < Count then FillChar(List[FromIndex], (ToIndex - FromIndex) * SizeOf(List[0]), 0) else FillChar(List[FromIndex], Count * SizeOf(List[0]), 0); end else if FromIndex > ToIndex then begin if (FromIndex - ToIndex) < Count then FillChar(List[ToIndex + Count], (FromIndex - ToIndex) * SizeOf(List[0]), 0) else FillChar(List[FromIndex], Count * SizeOf(List[0]), 0); end; end; end; {$ENDIF CLR} procedure MoveArray(var List: TDynSingleArray; FromIndex, ToIndex, Count: Integer); overload; {$IFDEF CLR} var I: Integer; begin if FromIndex < ToIndex then begin for I := Count - 1 downto 0 do List[ToIndex + I] := List[FromIndex + I]; if (ToIndex - FromIndex) < Count then // overlapped source and target for I := 0 to ToIndex - FromIndex - 1 do List[FromIndex + I] := 0.0 else // independant for I := 0 to Count - 1 do List[FromIndex + I] := 0.0; end else if FromIndex > ToIndex then begin for I := 0 to Count - 1 do List[ToIndex + I] := List[FromIndex + I]; if (FromIndex - ToIndex) < Count then // overlapped source and target for I := Count - FromIndex + ToIndex to Count - 1 do List[FromIndex + I] := 0.0 else // independant for I := 0 to Count - 1 do List[FromIndex + I] := 0.0; end; end; {$ELSE} begin if Count > 0 then begin Move(List[FromIndex], List[ToIndex], Count * SizeOf(List[0])); { Clean array } if FromIndex < ToIndex then begin if (ToIndex - FromIndex) < Count then FillChar(List[FromIndex], (ToIndex - FromIndex) * SizeOf(List[0]), 0) else FillChar(List[FromIndex], Count * SizeOf(List[0]), 0); end else if FromIndex > ToIndex then begin if (FromIndex - ToIndex) < Count then FillChar(List[ToIndex + Count], (FromIndex - ToIndex) * SizeOf(List[0]), 0) else FillChar(List[FromIndex], Count * SizeOf(List[0]), 0); end; end; end; {$ENDIF CLR} procedure MoveArray(var List: TDynDoubleArray; FromIndex, ToIndex, Count: Integer); overload; {$IFDEF CLR} var I: Integer; begin if FromIndex < ToIndex then begin for I := Count - 1 downto 0 do List[ToIndex + I] := List[FromIndex + I]; if (ToIndex - FromIndex) < Count then // overlapped source and target for I := 0 to ToIndex - FromIndex - 1 do List[FromIndex + I] := 0.0 else // independant for I := 0 to Count - 1 do List[FromIndex + I] := 0.0; end else if FromIndex > ToIndex then begin for I := 0 to Count - 1 do List[ToIndex + I] := List[FromIndex + I]; if (FromIndex - ToIndex) < Count then // overlapped source and target for I := Count - FromIndex + ToIndex to Count - 1 do List[FromIndex + I] := 0.0 else // independant for I := 0 to Count - 1 do List[FromIndex + I] := 0.0; end; end; {$ELSE} begin if Count > 0 then begin Move(List[FromIndex], List[ToIndex], Count * SizeOf(List[0])); { Clean array } if FromIndex < ToIndex then begin if (ToIndex - FromIndex) < Count then FillChar(List[FromIndex], (ToIndex - FromIndex) * SizeOf(List[0]), 0) else FillChar(List[FromIndex], Count * SizeOf(List[0]), 0); end else if FromIndex > ToIndex then begin if (FromIndex - ToIndex) < Count then FillChar(List[ToIndex + Count], (FromIndex - ToIndex) * SizeOf(List[0]), 0) else FillChar(List[FromIndex], Count * SizeOf(List[0]), 0); end; end; end; {$ENDIF CLR} {$IFNDEF FPC} procedure MoveArray(var List: TDynExtendedArray; FromIndex, ToIndex, Count: Integer); overload; {$IFDEF CLR} var I: Integer; begin if FromIndex < ToIndex then begin for I := Count - 1 downto 0 do List[ToIndex + I] := List[FromIndex + I]; if (ToIndex - FromIndex) < Count then // overlapped source and target for I := 0 to ToIndex - FromIndex - 1 do List[FromIndex + I] := 0.0 else // independant for I := 0 to Count - 1 do List[FromIndex + I] := 0.0; end else if FromIndex > ToIndex then begin for I := 0 to Count - 1 do List[ToIndex + I] := List[FromIndex + I]; if (FromIndex - ToIndex) < Count then // overlapped source and target for I := Count - FromIndex + ToIndex to Count - 1 do List[FromIndex + I] := 0.0 else // independant for I := 0 to Count - 1 do List[FromIndex + I] := 0.0; end; end; {$ELSE} begin if Count > 0 then begin Move(List[FromIndex], List[ToIndex], Count * SizeOf(List[0])); { Clean array } if FromIndex < ToIndex then begin if (ToIndex - FromIndex) < Count then FillChar(List[FromIndex], (ToIndex - FromIndex) * SizeOf(List[0]), 0) else FillChar(List[FromIndex], Count * SizeOf(List[0]), 0); end else if FromIndex > ToIndex then begin if (FromIndex - ToIndex) < Count then FillChar(List[ToIndex + Count], (FromIndex - ToIndex) * SizeOf(List[0]), 0) else FillChar(List[FromIndex], Count * SizeOf(List[0]), 0); end; end; end; {$ENDIF CLR} {$ENDIF FPC} procedure MoveArray(var List: TDynIntegerArray; FromIndex, ToIndex, Count: Integer); overload; {$IFDEF CLR} var I: Integer; begin if FromIndex < ToIndex then begin for I := Count - 1 downto 0 do List[ToIndex + I] := List[FromIndex + I]; if (ToIndex - FromIndex) < Count then // overlapped source and target for I := 0 to ToIndex - FromIndex - 1 do List[FromIndex + I] := 0 else // independant for I := 0 to Count - 1 do List[FromIndex + I] := 0; end else if FromIndex > ToIndex then begin for I := 0 to Count - 1 do List[ToIndex + I] := List[FromIndex + I]; if (FromIndex - ToIndex) < Count then // overlapped source and target for I := Count - FromIndex + ToIndex to Count - 1 do List[FromIndex + I] := 0 else // independant for I := 0 to Count - 1 do List[FromIndex + I] := 0; end; end; {$ELSE} begin if Count > 0 then begin Move(List[FromIndex], List[ToIndex], Count * SizeOf(List[0])); { Clean array } if FromIndex < ToIndex then begin if (ToIndex - FromIndex) < Count then FillChar(List[FromIndex], (ToIndex - FromIndex) * SizeOf(List[0]), 0) else FillChar(List[FromIndex], Count * SizeOf(List[0]), 0); end else if FromIndex > ToIndex then begin if (FromIndex - ToIndex) < Count then FillChar(List[ToIndex + Count], (FromIndex - ToIndex) * SizeOf(List[0]), 0) else FillChar(List[FromIndex], Count * SizeOf(List[0]), 0); end; end; end; {$ENDIF CLR} procedure MoveArray(var List: TDynCardinalArray; FromIndex, ToIndex, Count: Integer); overload; {$IFDEF CLR} var I: Integer; begin if FromIndex < ToIndex then begin for I := Count - 1 downto 0 do List[ToIndex + I] := List[FromIndex + I]; if (ToIndex - FromIndex) < Count then // overlapped source and target for I := 0 to ToIndex - FromIndex - 1 do List[FromIndex + I] := 0 else // independant for I := 0 to Count - 1 do List[FromIndex + I] := 0; end else if FromIndex > ToIndex then begin for I := 0 to Count - 1 do List[ToIndex + I] := List[FromIndex + I]; if (FromIndex - ToIndex) < Count then // overlapped source and target for I := Count - FromIndex + ToIndex to Count - 1 do List[FromIndex + I] := 0 else // independant for I := 0 to Count - 1 do List[FromIndex + I] := 0; end; end; {$ELSE} begin if Count > 0 then begin Move(List[FromIndex], List[ToIndex], Count * SizeOf(List[0])); { Clean array } if FromIndex < ToIndex then begin if (ToIndex - FromIndex) < Count then FillChar(List[FromIndex], (ToIndex - FromIndex) * SizeOf(List[0]), 0) else FillChar(List[FromIndex], Count * SizeOf(List[0]), 0); end else if FromIndex > ToIndex then begin if (FromIndex - ToIndex) < Count then FillChar(List[ToIndex + Count], (FromIndex - ToIndex) * SizeOf(List[0]), 0) else FillChar(List[FromIndex], Count * SizeOf(List[0]), 0); end; end; end; {$ENDIF CLR} procedure MoveArray(var List: TDynInt64Array; FromIndex, ToIndex, Count: Integer); overload; {$IFDEF CLR} var I: Integer; begin if FromIndex < ToIndex then begin for I := Count - 1 downto 0 do List[ToIndex + I] := List[FromIndex + I]; if (ToIndex - FromIndex) < Count then // overlapped source and target for I := 0 to ToIndex - FromIndex - 1 do List[FromIndex + I] := 0 else // independant for I := 0 to Count - 1 do List[FromIndex + I] := 0; end else if FromIndex > ToIndex then begin for I := 0 to Count - 1 do List[ToIndex + I] := List[FromIndex + I]; if (FromIndex - ToIndex) < Count then // overlapped source and target for I := Count - FromIndex + ToIndex to Count - 1 do List[FromIndex + I] := 0 else // independant for I := 0 to Count - 1 do List[FromIndex + I] := 0; end; end; {$ELSE} begin if Count > 0 then begin Move(List[FromIndex], List[ToIndex], Count * SizeOf(List[0])); { Clean array } if FromIndex < ToIndex then begin if (ToIndex - FromIndex) < Count then FillChar(List[FromIndex], (ToIndex - FromIndex) * SizeOf(List[0]), 0) else FillChar(List[FromIndex], Count * SizeOf(List[0]), 0); end else if FromIndex > ToIndex then begin if (FromIndex - ToIndex) < Count then FillChar(List[ToIndex + Count], (FromIndex - ToIndex) * SizeOf(List[0]), 0) else FillChar(List[FromIndex], Count * SizeOf(List[0]), 0); end; end; end; {$ENDIF CLR} procedure MoveChar(const Source: string; FromIndex: Integer; var Dest: string; ToIndex, Count: Integer); {$IFDEF CLR} var I: Integer; Buf: array of Char; begin Buf := Dest.ToCharArray; if FromIndex <= ToIndex then for I := 0 to Count - 1 do Buf[ToIndex + I] := Source[FromIndex + I] else for I := Count - 1 downto 0 do Buf[ToIndex + I] := Source[FromIndex + I]; Dest := System.String.Create(Buf); {$ELSE} begin Move(Source[FromIndex + 1], Dest[ToIndex + 1], Count * SizeOf(Char)); {$ENDIF CLR} end; {$IFDEF CLR} function GetBytesEx(const Value): TBytes; begin if TObject(Value) is TBytes then Result := Copy(TBytes(Value)) else if TObject(Value) is TDynByteArray then Result := Copy(TDynByteArray(Value)) else if TObject(Value) is System.Enum then // e.g. TIntegerSet BitConverter.GetBytes(UInt32(Value)) { TODO : Add further types } else raise EJclError.CreateFmt(RsEGetBytesExFmt, [TObject(Value).GetType.FullName]); end; procedure SetBytesEx(var Value; Bytes: TBytes); begin if TObject(Value) is TBytes then Value := Copy(Bytes) else if TObject(Value) is TDynByteArray then Value := Copy(Bytes) else if TObject(Value) is System.Enum then // e.g. TIntegerSet Value := BitConverter.ToUInt32(Bytes, 0) { TODO : Add further types } else raise EJclError.CreateFmt(RsESetBytesExFmt, [TObject(Value).GetType.FullName]); end; procedure SetIntegerSet(var DestSet: TIntegerSet; Value: UInt32); begin DestSet := TIntegerSet(Value); end; function AnsiByteArrayStringLen(Data: TBytes): Integer; var I: Integer; begin for I := 0 to High(Data) do if Data[I] = 0 then begin Result := I + 1; Exit; end; Result := Length(Data); end; function StringToAnsiByteArray(const S: string): TBytes; var I: Integer; AnsiS: AnsiString; begin AnsiS := S; // convert to AnsiString SetLength(Result, Length(AnsiS)); for I := 0 to High(Result) do Result[I] := Byte(AnsiS[I + 1]); end; function AnsiByteArrayToString(const Data: TBytes; Count: Integer): string; var I: Integer; AnsiS: AnsiString; begin if Length(Data) < Count then Count := Length(Data); SetLength(AnsiS, Count); for I := 0 to Length(AnsiS) - 1 do AnsiS[I + 1] := AnsiChar(Data[I]); Result := AnsiS; // convert to System.String end; // == { TStringAnsiBufferStreamHelper } ====================================== function TStringAnsiBufferStreamHelper.WriteStringAnsiBuffer(const Buffer: string; StrLen: Integer): Integer; begin Result := WriteStringAnsiBuffer(Copy(Buffer, StrLen)); end; function TStringAnsiBufferStreamHelper.WriteStringAnsiBuffer(const Buffer: string): Integer; var Bytes: TBytes; begin Bytes := StringToAnsiByteArray(Buffer); Result := Write(Bytes, Length(Bytes)); end; function TStringAnsiBufferStreamHelper.ReadStringAnsiBuffer(var Buffer: string; AnsiLen: Integer): Integer; var Bytes: TBytes; begin if AnsiLen > 0 then begin SetLength(Bytes, AnsiLen); Result := Read(Bytes, AnsiLen); Buffer := AnsiByteArrayToString(Bytes, Result); end else begin Buffer := ''; Result := 0; end; end; function TStringAnsiBufferStreamHelper.WriteStringAnsiBuffer(const Buffer: AnsiString; StrLen: Integer): Integer; begin Result := WriteStringAnsiBuffer(Copy(Buffer, StrLen)); end; function TStringAnsiBufferStreamHelper.WriteStringAnsiBuffer(const Buffer: AnsiString): Integer; var Bytes: TBytes; begin Bytes := BytesOf(Buffer); Result := Write(Bytes, Length(Bytes)); end; function TStringAnsiBufferStreamHelper.ReadStringAnsiBuffer(var Buffer: AnsiString; AnsiLen: Integer): Integer; var Bytes: TBytes; begin if AnsiLen > 0 then begin SetLength(Bytes, AnsiLen); Result := Read(Bytes, AnsiLen); SetLength(Bytes, Result); Buffer := StringOf(Bytes); end else begin Buffer := ''; Result := 0; end; end; {$ELSE} function BytesOf(const Value: AnsiString): TBytes; begin SetLength(Result, Length(Value)); if Value <> '' then Move(Pointer(Value)^, Result[0], Length(Value)); end; {$IFDEF COMPILER6_UP} function BytesOf(const Value: WideString): TBytes; begin if Value <> '' then Result := JclBase.BytesOf(AnsiString(Value)) else SetLength(Result, 0); end; function BytesOf(const Value: WideChar): TBytes; begin Result := JclBase.BytesOf(WideString(Value)); end; {$ENDIF COMPILER6_UP} function BytesOf(const Value: AnsiChar): TBytes; begin SetLength(Result, 1); Result[0] := Byte(Value); end; function StringOf(const Bytes: array of Byte): AnsiString; begin if Length(Bytes) > 0 then begin SetLength(Result, Length(Bytes)); Move(Bytes[0], Pointer(Result)^, Length(Bytes)); end else Result := ''; end; function StringOf(const Bytes: Pointer; Size: Cardinal): AnsiString; begin if (Bytes <> nil) and (Size > 0) then begin SetLength(Result, Size); Move(Bytes^, Pointer(Result)^, Size); end else Result := ''; end; {$ENDIF CLR} //== { EJclWin32Error } ====================================================== {$IFDEF MSWINDOWS} constructor EJclWin32Error.Create(const Msg: string); begin {$IFDEF CLR} inherited Create(''); // this works because the GC cleans the memory {$ENDIF CLR} FLastError := GetLastError; FLastErrorMsg := SysErrorMessage(FLastError); inherited CreateFmt(Msg + NativeLineBreak + RsWin32Prefix, [FLastErrorMsg, FLastError]); end; constructor EJclWin32Error.CreateFmt(const Msg: string; const Args: array of const); begin {$IFDEF CLR} inherited Create(''); // this works because the GC cleans the memory {$ENDIF CLR} FLastError := GetLastError; FLastErrorMsg := SysErrorMessage(FLastError); inherited CreateFmt(Msg + NativeLineBreak + Format(RsWin32Prefix, [FLastErrorMsg, FLastError]), Args); end; {$IFNDEF CLR} constructor EJclWin32Error.CreateRes(Ident: Integer); begin FLastError := GetLastError; FLastErrorMsg := SysErrorMessage(FLastError); inherited CreateFmt(LoadStr(Ident) + NativeLineBreak + RsWin32Prefix, [FLastErrorMsg, FLastError]); end; constructor EJclWin32Error.CreateRes(ResStringRec: PResStringRec); begin FLastError := GetLastError; FLastErrorMsg := SysErrorMessage(FLastError); {$IFDEF FPC} inherited CreateFmt(ResStringRec^ + AnsiLineBreak + RsWin32Prefix, [FLastErrorMsg, FLastError]); {$ELSE} inherited CreateFmt(LoadResString(ResStringRec) + NativeLineBreak + RsWin32Prefix, [FLastErrorMsg, FLastError]); {$ENDIF FPC} end; {$ENDIF ~CLR} {$ENDIF MSWINDOWS} // Int64 support procedure I64ToCardinals(I: Int64; var LowPart, HighPart: Cardinal); begin {$IFDEF CLR} LowPart := Cardinal(I and $00000000FFFFFFFF); HighPart := Cardinal(I shr 32); {$ELSE} LowPart := TULargeInteger(I).LowPart; HighPart := TULargeInteger(I).HighPart; {$ENDIF CLR} end; procedure CardinalsToI64(var I: Int64; const LowPart, HighPart: Cardinal); begin {$IFDEF CLR} I := Int64(HighPart) shl 16 or LowPart; {$ELSE} TULargeInteger(I).LowPart := LowPart; TULargeInteger(I).HighPart := HighPart; {$ENDIF CLR} end; // Cross Platform Compatibility {$IFNDEF XPLATFORM_RTL} procedure RaiseLastOSError; begin RaiseLastWin32Error; end; {$ENDIF ~XPLATFORM_RTL} {$OVERFLOWCHECKS OFF} function Addr64ToAddr32(const Value: TJclAddr64): TJclAddr32; begin if (Value shr 32) = 0 then Result := Value else {$IFDEF CLR} raise EJclAddr64Exception.CreateFmt(RsCantConvertAddr64, [HexPrefix, Value]); {$ELSE ~CLR} raise EJclAddr64Exception.CreateResFmt(@RsCantConvertAddr64, [HexPrefix, Value]); {$ENDIF ~CLR} end; function Addr32ToAddr64(const Value: TJclAddr32): TJclAddr64; begin Result := Value; end; {$IFDEF OVERFLOWCHECKS_ON} {$OVERFLOWCHECKS ON} {$ENDIF OVERFLOWCHECKS_ON} {$IFDEF SUPPORTS_GENERICS} //=== { TEquatable } ====================================================== function TEquatable.TestEquals(Other: T): Boolean; begin if Other = nil then Result := False else Result := GetHashCode = Other.GetHashCode; end; function TEquatable.TestEquals(A, B: T): Boolean; begin if A = nil then Result := B = nil else if B = nil then Result := False else Result := A.GetHashCode = B.GetHashCode; end; function TEquatable.GetHashCode2(Obj: T): Integer; begin if Obj = nil then Result := 0 else Result := Obj.GetHashCode; end; {$ENDIF SUPPORTS_GENERICS} procedure LoadAnsiReplacementCharacter; {$IFDEF MSWINDOWS} {$IFDEF CLR} begin AnsiReplacementCharacter := '?'; end; {$ELSE ~CLR} var CpInfo: TCpInfo; begin if GetCPInfo(CP_ACP, CpInfo) then AnsiReplacementCharacter := AnsiChar(Chr(CpInfo.DefaultChar[0])) else raise EJclInternalError.CreateRes(@RsEReplacementChar); end; {$ENDIF ~CLR} {$ELSE ~MSWINDOWS} begin AnsiReplacementCharacter := '?'; end; {$ENDIF ~MSWINDOWS} initialization LoadAnsiReplacementCharacter; {$IFDEF UNITVERSIONING} RegisterUnitVersion(HInstance, UnitVersioning); {$ENDIF UNITVERSIONING} finalization {$IFDEF UNITVERSIONING} UnregisterUnitVersion(HInstance); {$ENDIF UNITVERSIONING} end.