restemplate/indy/System/IdGlobal.pas

9180 lines
294 KiB
Plaintext

{
$Project$
$Workfile$
$Revision$
$DateUTC$
$Id$
This file is part of the Indy (Internet Direct) project, and is offered
under the dual-licensing agreement described on the Indy website.
(http://www.indyproject.org/)
Copyright:
(c) 1993-2005, Chad Z. Hower and the Indy Pit Crew. All rights reserved.
}
{
$Log$
}
{
Rev 1.54 2/9/2005 8:45:38 PM JPMugaas
Should work.
Rev 1.53 2/8/05 6:37:38 PM RLebeau
Added default value to ASize parameter of ReadStringFromStream()
Rev 1.52 2/8/05 5:57:10 PM RLebeau
added AppendString(), CopyTIdLongWord(), and CopyTIdString() functions
Rev 1.51 1/31/05 6:01:40 PM RLebeau
Renamed GetCurrentThreadHandle() to CurrentThreadId() and changed the return
type from THandle to to TIdPID.
Reworked conditionals for SetThreadName() and updated the implementation to
support naming threads under DotNet.
Rev 1.50 1/27/05 3:40:04 PM RLebeau
Updated BytesToShort() to actually use the AIndex parameter that was added
earlier.
Rev 1.49 1/24/2005 7:35:36 PM JPMugaas
Foxed ma,e om CopyTIdIPV6Address/
Rev 1.48 1/17/2005 7:26:44 PM JPMugaas
Made an IPv6 address byte copy function.
Rev 1.47 1/15/2005 6:01:38 PM JPMugaas
Removed some new procedures for extracting int values from a TIdBytes and
made some other procedures have an optional index paramter.
Rev 1.46 1/13/05 11:11:20 AM RLebeau
Changed BytesToRaw() to pass TIdBytes by 'const' rather than by 'var'
Rev 1.45 1/8/2005 3:56:58 PM JPMugaas
Added routiens for copying integer values to and from TIdBytes. These are
useful for some protocols.
Rev 1.44 24/11/2004 16:26:24 ANeillans
GetTickCount corrected, as per Paul Cooper's post in
atozedsoftware.indy.general.
Rev 1.43 11/13/04 10:47:28 PM RLebeau
Fixed compiler errors
Rev 1.42 11/12/04 1:02:42 PM RLebeau
Added RawToBytesF() and BytesToRaw() functions
Added asserts to BytesTo...() functions
Rev 1.41 10/26/2004 8:20:02 PM JPMugaas
Fixed some oversights with conversion. OOPS!!!
Rev 1.40 10/26/2004 8:00:54 PM JPMugaas
Now uses TIdStrings for DotNET portability.
Rev 1.39 2004.10.26 7:35:16 PM czhower
Moved IndyCat to CType in IdBaseComponent
Rev 1.38 24/10/2004 21:29:52 ANeillans
Corrected error in GetTickCount,
was Result := Trunc(nTime / (Freq * 1000))
should be Result := Trunc((nTime / Freq) * 1000)
Rev 1.37 20/10/2004 01:08:20 CCostelloe
Bug fix
Rev 1.36 28.09.2004 20:36:58 Andreas Hausladen
Works now with Delphi 5
Rev 1.35 9/23/2004 11:36:04 PM DSiders
Modified Ticks function (Win32) to correct RangeOverflow error. (Reported by
Mike Potter)
Rev 1.34 24.09.2004 02:16:04 Andreas Hausladen
Added ReadTIdBytesFromStream and ReadCharFromStream function to supress .NET
warnings.
Rev 1.33 9/5/2004 2:55:00 AM JPMugaas
function BytesToWord(const AValue: TIdBytes): Word; was not listed in the
interface.
Rev 1.32 04.09.2004 17:12:56 Andreas Hausladen
New PosIdx function (without pointers)
Rev 1.31 27.08.2004 22:02:20 Andreas Hausladen
Speed optimization ("const" for string parameters)
rewritten PosIdx function with AStartPos = 0 handling
new ToArrayF() functions (faster in native code because the TIdBytes array
must have the required len before the ToArrayF function is called)
Rev 1.30 24.08.2004 19:48:28 Andreas Hausladen
Some optimizations
Removed IFDEF for IdDelete and IdInsert
Rev 1.29 8/17/2004 2:54:08 PM JPMugaas
Fix compiler warning about widening operends. Int64 can sometimes incur a
performance penalty.
Rev 1.28 8/15/04 5:57:06 PM RLebeau
Tweaks to PosIdx()
Rev 1.27 7/23/04 10:13:16 PM RLebeau
Updated ReadStringFromStream() to resize the result using the actual number
of bytes read from the stream
Rev 1.26 7/18/2004 2:45:38 PM DSiders
Added localization comments.
Rev 1.25 7/9/04 4:25:20 PM RLebeau
Renamed ToBytes(raw) to RawToBytes() to fix an ambiquity error with
ToBytes(TIdBytes)
Rev 1.24 7/9/04 4:07:06 PM RLebeau
Compiler fix for TIdBaseStream.Write()
Rev 1.23 09/07/2004 22:17:52 ANeillans
Fixed IdGlobal.pas(761) Error: ';', ')' or '=' expected but ':=' found
Rev 1.22 7/8/04 11:56:10 PM RLebeau
Added additional parameters to BytesToString()
Bug fix for ReadStringFromStream()
Updated TIdBaseStream.Write() to use ToBytes()
Rev 1.21 7/8/04 4:22:36 PM RLebeau
Added ToBytes() overload for raw pointers under non-DotNet platfoms.
Rev 1.20 2004.07.03 19:39:38 czhower
UTF8
Rev 1.19 6/15/2004 7:18:06 PM JPMugaas
IdInsert for stuff needing to call the Insert procedure.
Rev 1.18 2004.06.13 8:06:46 PM czhower
.NET update
Rev 1.17 6/11/2004 8:28:30 AM DSiders
Added "Do not Localize" comments.
Rev 1.16 2004.06.08 7:11:14 PM czhower
Typo fix.
Rev 1.15 2004.06.08 6:34:48 PM czhower
.NET bug with Ticks workaround.
Rev 1.14 07/06/2004 21:30:32 CCostelloe
Kylix 3 changes
Rev 1.13 5/3/04 12:17:44 PM RLebeau
Updated ToBytes(string) and BytesToString() under DotNet to use
System.Text.Encoding.ASCII instead of AnsiEncoding
Rev 1.12 4/24/04 12:41:36 PM RLebeau
Conversion support to/from TIdBytes for Char values
Rev 1.11 4/18/04 2:45:14 PM RLebeau
Conversion support to/from TIdBytes for Int64 values
Rev 1.10 2004.04.08 4:50:06 PM czhower
Comments
Rev 1.9 2004.04.08 1:45:42 AM czhower
tiny string optimization
Rev 1.8 4/7/2004 3:20:50 PM JPMugaas
PosIdx was not working in DotNET. In DotNET, it was returning a Pos value
without adding the startvalue -1. It was throwing off the FTP list parsers.
Two uneeded IFDEF's were removed.
Rev 1.7 2004.03.13 5:51:28 PM czhower
Fixed stack overflow in Sleep for .net
Rev 1.6 3/6/2004 5:16:02 PM JPMugaas
Bug 67 fixes. Do not write to const values.
Rev 1.5 3/6/2004 4:54:12 PM JPMugaas
Write to const bug fix.
Rev 1.4 2/17/2004 12:02:44 AM JPMugaas
A few routines that might be needed later for RFC 3490 support.
Rev 1.3 2/16/2004 1:56:04 PM JPMugaas
Moved some routines here to lay the groundwork for RFC 3490 support. Started
work on RFC 3490 support.
Rev 1.2 2/11/2004 5:12:30 AM JPMugaas
Moved IPv6 address definition here.
I also made a function for converting a TIdBytes to an IPv6 address.
Rev 1.1 2004.02.03 3:15:52 PM czhower
Updates to move to System.
Rev 1.0 2004.02.03 2:28:30 PM czhower
Move
Rev 1.91 2/1/2004 11:16:04 PM BGooijen
ToBytes
Rev 1.90 2/1/2004 1:28:46 AM JPMugaas
Disabled IdPort functionality in DotNET. It can't work there in it's current
form and trying to get it to work will introduce more problems than it
solves. It was only used by the bindings editor and we did something
different in DotNET so IdPorts wouldn't used there.
Rev 1.89 2004.01.31 1:51:10 AM czhower
IndyCast for VB.
Rev 1.88 30/1/2004 4:47:46 PM SGrobety
Added "WriteMemoryStreamToStream" to take care of Win32/dotnet difference in
the TMemoryStream.Memory type and the Write buffer parameter
Rev 1.87 1/30/2004 11:59:24 AM BGooijen
Added WriteTIdBytesToStream, because we can convert almost everything to
TIdBytes, and TIdBytes couldn't be written to streams easily
Rev 1.86 2004.01.27 11:44:36 PM czhower
.Net Updates
Rev 1.85 2004.01.27 8:15:54 PM czhower
Fixed compile error + .net helper.
Rev 1.84 27/1/2004 1:55:10 PM SGrobety
TIdStringStream introduced to fix a bug in DOTNET TStringStream
implementation.
Rev 1.83 2004.01.27 1:42:00 AM czhower
Added parameter check
Rev 1.82 25/01/2004 21:55:40 CCostelloe
Added portable IdFromBeginning/FromCurrent/FromEnd, to be used instead of
soFromBeginning/soBeginning, etc.
Rev 1.81 24/01/2004 20:18:46 CCostelloe
Added IndyCompareStr (to be used in place of AnsiCompareStr for .NET
compatibility)
Rev 1.80 2004.01.23 9:56:30 PM czhower
CharIsInSet now checks length and returns false if no character.
Rev 1.79 2004.01.23 9:49:40 PM czhower
CharInSet no longer accepts -1, was unneeded and redundant.
Rev 1.78 1/22/2004 5:47:46 PM SPerry
fixed CharIsInSet
Rev 1.77 2004.01.22 5:33:46 PM czhower
TIdCriticalSection
Rev 1.76 2004.01.22 3:23:18 PM czhower
IsCharInSet
Rev 1.75 2004.01.22 2:00:14 PM czhower
iif change
Rev 1.74 14/01/2004 00:17:34 CCostelloe
Added IndyLowerCase/IndyUpperCase to replace AnsiLowerCase/AnsiUpperCase for
.NET code
Rev 1.73 1/11/2004 9:50:54 PM BGooijen
Added ToBytes function for Socks
Rev 1.72 2003.12.31 7:32:40 PM czhower
InMainThread now for .net too.
Rev 1.71 2003.12.29 6:48:38 PM czhower
TextIsSame
Rev 1.70 2003.12.28 1:11:04 PM czhower
Conditional typo fixed.
Rev 1.69 2003.12.28 1:05:48 PM czhower
.Net changes.
Rev 1.68 5/12/2003 9:11:00 AM GGrieve
Add WriteStringToStream
Rev 1.67 5/12/2003 12:32:48 AM GGrieve
fix DotNet warnings
Rev 1.66 22/11/2003 12:03:02 AM GGrieve
fix IdMultiPathFormData.pas implementation
Rev 1.65 11/15/2003 1:15:36 PM VVassiliev
Move AppendByte from IdDNSCommon to IdCoreGlobal
Rev 1.64 10/28/2003 8:43:48 PM BGooijen
compiles, and removed call to setstring
Rev 1.63 2003.10.24 10:44:50 AM czhower
IdStream implementation, bug fixes.
Rev 1.62 10/18/2003 4:53:18 PM BGooijen
Added ToHex
Rev 1.61 2003.10.17 6:17:24 PM czhower
Some parts moved to stream
Rev 1.60 10/15/2003 8:28:16 PM DSiders
Added localization comments.
Rev 1.59 2003.10.14 9:27:12 PM czhower
Fixed compile erorr with missing )
Rev 1.58 10/14/2003 3:31:04 PM SPerry
Modified ByteToHex() and IPv4ToHex
Rev 1.57 10/13/2003 5:06:46 PM BGooijen
Removed local constant IdOctalDigits in favor of the unit constant. - attempt
2
Rev 1.56 10/13/2003 10:07:12 AM DSiders
Reverted prior change; local constant for IdOctalDigits is restored.
Rev 1.55 10/12/2003 11:55:42 AM DSiders
Removed local constant IdOctalDigits in favor of the unit constant.
Rev 1.54 2003.10.11 5:47:22 PM czhower
-VCL fixes for servers
-Chain suport for servers (Super core)
-Scheduler upgrades
-Full yarn support
Rev 1.53 10/8/2003 10:14:34 PM GGrieve
add WriteStringToStream
Rev 1.52 10/8/2003 9:55:30 PM GGrieve
Add IdDelete
Rev 1.51 10/7/2003 11:33:30 PM GGrieve
Fix ReadStringFromStream
Rev 1.50 10/7/2003 10:07:30 PM GGrieve
Get IdHTTP compiling for DotNet
Rev 1.49 6/10/2003 5:48:48 PM SGrobety
DotNet updates
Rev 1.48 10/5/2003 12:26:46 PM BGooijen
changed parameter names at some places
Rev 1.47 10/4/2003 7:08:26 PM BGooijen
added some conversion routines type->TIdBytes->type, and fixed existing ones
Rev 1.46 10/4/2003 3:53:40 PM BGooijen
added some ToBytes functions
Rev 1.45 04/10/2003 13:38:28 HHariri
Write(Integer) support
Rev 1.44 10/3/2003 10:44:54 PM BGooijen
Added WriteBytesToStream
Rev 1.43 2003.10.02 8:29:14 PM czhower
Changed names of byte conversion routines to be more readily understood and
not to conflict with already in use ones.
Rev 1.42 10/2/2003 5:15:16 PM BGooijen
Added Grahame's functions
Rev 1.41 10/1/2003 8:02:20 PM BGooijen
Removed some ifdefs and improved code
Rev 1.40 2003.10.01 9:10:58 PM czhower
.Net
Rev 1.39 2003.10.01 2:46:36 PM czhower
.Net
Rev 1.38 2003.10.01 2:30:36 PM czhower
.Net
Rev 1.37 2003.10.01 12:30:02 PM czhower
.Net
Rev 1.35 2003.10.01 1:12:32 AM czhower
.Net
Rev 1.34 2003.09.30 7:37:14 PM czhower
Typo fix.
Rev 1.33 30/9/2003 3:58:08 PM SGrobety
More .net updates
Rev 1.31 2003.09.30 3:19:30 PM czhower
Updates for .net
Rev 1.30 2003.09.30 1:22:54 PM czhower
Stack split for DotNet
Rev 1.29 2003.09.30 12:09:36 PM czhower
DotNet changes.
Rev 1.28 2003.09.30 10:36:02 AM czhower
Moved stack creation to IdStack
Added DotNet stack.
Rev 1.27 9/29/2003 03:03:28 PM JPMugaas
Changed CIL to DOTNET.
Rev 1.26 9/28/2003 04:22:00 PM JPMugaas
IFDEF'ed out MemoryPos in NET because that will not work there.
Rev 1.25 9/26/03 11:20:50 AM RLebeau
Updated defines used with SetThreadName() to allow it to work under BCB6.
Rev 1.24 9/24/2003 11:42:42 PM JPMugaas
Minor changes to help compile under NET
Rev 1.23 2003.09.20 10:25:42 AM czhower
Added comment and chaned for D6 compat.
Rev 1.22 9/18/2003 07:43:12 PM JPMugaas
Moved GetThreadHandle to IdGlobals so the ThreadComponent can be in this
package.
Rev 1.21 9/8/2003 11:44:38 AM JPMugaas
Fix for problem that was introduced in an optimization.
Rev 1.20 2003.08.19 1:54:34 PM czhower
Removed warning
Rev 1.19 11/8/2003 6:25:44 PM SGrobety
IPv4ToDWord: Added overflow checking disabling ($Q+) and changed "* 256" by
"SHL 8".
Rev 1.18 2003.07.08 2:41:42 PM czhower
This time I saved the file before checking in.
Rev 1.16 7/1/2003 03:39:38 PM JPMugaas
Started numeric IP function API calls for more efficiency.
Rev 1.15 2003.07.01 3:49:56 PM czhower
Added SetThreadName
Rev 1.14 7/1/2003 12:03:56 AM BGooijen
Added functions to switch between IPv6 addresses in string and in
TIdIPv6Address form
Rev 1.13 6/30/2003 06:33:58 AM JPMugaas
Fix for range check error.
Rev 1.12 6/27/2003 04:43:30 PM JPMugaas
Made IPv4ToDWord overload that returns a flag for an error message.
Moved MakeCanonicalIPv4Address code into IPv4ToDWord because most of that
simply reduces IPv4 addresses into a DWord. That also should make the
function more useful in reducing various alternative forms of IPv4 addresses
down to DWords.
Rev 1.11 6/27/2003 01:19:38 PM JPMugaas
Added MakeCanonicalIPv4Address for converting various IPv4 address forms
(mentioned at http://www.pc-help.org/obscure.htm) into a standard dotted IP
address. Hopefully, we should soon support octal and hexidecimal addresses.
Rev 1.9 6/27/2003 04:36:08 AM JPMugaas
Function for converting DWord to IP adcdress.
Rev 1.8 6/26/2003 07:54:38 PM JPMugaas
Routines for converting standard dotted IPv4 addresses into dword,
hexidecimal, and octal forms.
Rev 1.7 5/11/2003 11:57:06 AM BGooijen
Added RaiseLastOSError
Rev 1.6 4/28/2003 03:19:00 PM JPMugaas
Made a function for obtaining the services file FQN. That's in case
something else besides IdPorts needs it.
Rev 1.5 2003.04.16 10:06:42 PM czhower
Moved DebugOutput to IdCoreGlobal
Rev 1.4 12/29/2002 2:15:30 PM JPMugaas
GetCurrentThreadHandle function created as per Bas's instructions. Moved
THandle to IdCoreGlobal for this function.
Rev 1.3 12-15-2002 17:02:58 BGooijen
Added comments to TIdExtList
Rev 1.2 12-15-2002 16:45:42 BGooijen
Added TIdList
Rev 1.1 29/11/2002 10:08:50 AM SGrobety Version: 1.1
Changed GetTickCount to use high-performance timer if available under windows
Rev 1.0 21/11/2002 12:36:18 PM SGrobety Version: Indy 10
Rev 1.0 11/13/2002 08:41:24 AM JPMugaas
}
unit IdGlobal;
interface
{$I IdCompilerDefines.inc}
uses
SysUtils,
{$IFDEF DOTNET}
System.Collections.Specialized,
System.net,
System.net.Sockets,
System.Diagnostics,
System.Threading,
System.IO,
System.Text,
{$ELSE}
{$IFDEF HAS_UNIT_Generics_Collections}
System.Generics.Collections,
{$ENDIF}
{$ENDIF}
{$IFDEF WINDOWS}
{$IFDEF FPC}
windows,
{$ELSE}
Windows,
{$ENDIF}
{$ENDIF}
Classes,
syncobjs,
{$IFDEF UNIX}
{$IFDEF KYLIXCOMPAT}
Libc,
{$ELSE}
{$IFDEF FPC}
DynLibs, // better add DynLibs only for fpc
{$ENDIF}
{$IFDEF USE_VCL_POSIX}
Posix.SysTypes, Posix.Pthread, Posix.Unistd,
{$ENDIF}
{$IFDEF USE_BASEUNIX}
BaseUnix, Unix, Sockets, UnixType,
{$ENDIF}
{$IFDEF USE_ICONV_ENC}iconvenc, {$ENDIF}
{$ENDIF}
{$IFDEF DARWIN}
{$IFNDEF FPC}
//RLebeau: FPC does not provide mach_timebase_info() and mach_absolute_time() yet...
Macapi.Mach,
{$ENDIF}
{$ENDIF}
{$ENDIF}
IdException;
{$IFNDEF HAS_Int8}
type
Int8 = {$IFDEF DOTNET}System.SByte{$ELSE}Shortint{$ENDIF};
{$NODEFINE Int8}
{$ENDIF}
{$IFNDEF HAS_PInt8}
{$IFNDEF DOTNET}
type
PInt8 = PShortint;
{$NODEFINE PInt8}
{$ENDIF}
{$ENDIF}
{$IFNDEF HAS_UInt8}
type
UInt8 = {$IFDEF DOTNET}System.Byte{$ELSE}Byte{$ENDIF};
{$NODEFINE UInt8}
{$ENDIF}
{$IFNDEF HAS_PUInt8}
{$IFNDEF DOTNET}
type
PUInt8 = PByte;
{$NODEFINE PUInt8}
{$ENDIF}
{$ENDIF}
{$IFNDEF HAS_Int16}
type
Int16 = Smallint;
{$NODEFINE Int16}
{$ENDIF}
{$IFNDEF HAS_PInt16}
{$IFNDEF DOTNET}
type
PInt16 = PSmallint;
{$NODEFINE PInt16}
{$ENDIF}
{$ENDIF}
{$IFNDEF HAS_UInt16}
type
UInt16 = Word;
{$NODEFINE UInt16}
{$ENDIF}
{$IFNDEF HAS_PUInt16}
{$IFNDEF DOTNET}
type
PUInt16 = PWord;
{$NODEFINE PUInt16}
{$ENDIF}
{$ENDIF}
{$IFNDEF HAS_Int32}
type
Int32 = Integer;
{$NODEFINE Int32}
{$ENDIF}
{$IFNDEF HAS_PInt32}
{$IFNDEF DOTNET}
type
PInt32 = PInteger;
{$NODEFINE PInt32}
{$ENDIF}
{$ENDIF}
{$IFNDEF HAS_UInt32}
type
UInt32 = Cardinal;
{$NODEFINE UInt32}
{$ENDIF}
{$IFNDEF HAS_PUInt32}
{$IFNDEF DOTNET}
type
PUInt32 = PCardinal;
{$NODEFINE PUInt32}
{$ENDIF}
{$ENDIF}
{$IFDEF HAS_UInt64}
{$DEFINE UInt64_IS_NATIVE}
// In C++Builder 2006 and 2007, UInt64 is emitted as signed __int64 in HPP
// files instead of as unsigned __int64. This causes conflicts in overloaded
// routines that have (U)Int64 parameters. This was fixed in C++Builder 2009...
{$IFNDEF BROKEN_UINT64_HPPEMIT}
type
TIdUInt64 = UInt64;
{$ENDIF}
{$ELSE}
{$IFDEF HAS_QWord}
{$DEFINE UInt64_IS_NATIVE}
type
UInt64 = QWord;
{$NODEFINE UInt64}
TIdUInt64 = QWord;
{$ELSE}
type
UInt64 = Int64;
{$NODEFINE UInt64}
{$ENDIF}
{$ENDIF}
{$IFDEF TIdUInt64_IS_NOT_NATIVE}
// For compilers that do not have a native UInt64 type, or for C++Builder
// 2006/2007 with its broken UInt64 HPP emit, let's define a record type
// that can hold UInt64 values, and then use it wherever UInt64 parameters
// are needed...
type
TIdUInt64 = packed record
case Integer of
0: (
{$IFDEF ENDIAN_BIG}
HighPart: UInt32;
LowPart: UInt32
{$ELSE}
LowPart: UInt32;
HighPart: UInt32
{$ENDIF}
);
1: (
QuadPart: UInt64
);
end;
{$NODEFINE TIdUInt64}
(*$HPPEMIT 'namespace Idglobal'*)
(*$HPPEMIT '{'*)
(*$HPPEMIT ' #pragma pack(push, 1)' *)
(*$HPPEMIT ' struct TIdUInt64'*)
(*$HPPEMIT ' {'*)
(*$HPPEMIT ' union {'*)
(*$HPPEMIT ' struct {'*)
{$IFDEF ENDIAN_BIG}
(*$HPPEMIT ' unsigned __int32 HighPart;'*)
(*$HPPEMIT ' unsigned __int32 LowPart;'*)
{$ELSE}
(*$HPPEMIT ' unsigned __int32 LowPart;'*)
(*$HPPEMIT ' unsigned __int32 HighPart;'*)
{$ENDIF}
(*$HPPEMIT ' };'*)
(*$HPPEMIT ' unsigned __int64 QuadPart;'*)
(*$HPPEMIT ' };'*)
(*$HPPEMIT ' TIdUInt64(unsigned __int64 value) { QuadPart = value; }'*)
(*$HPPEMIT ' operator unsigned __int64() const { return QuadPart; }'*)
(*$HPPEMIT ' };'*)
(*$HPPEMIT ' #pragma pack(pop)' *)
(*$HPPEMIT '}'*)
{$ENDIF}
const
{This is the only unit with references to OS specific units and IFDEFs. NO OTHER units
are permitted to do so except .pas files which are counterparts to dfm/xfm files, and only for
support of that.}
//We make the version things an Inc so that they can be managed independantly
//by the package builder.
{$I IdVers.inc}
{$IFNDEF HAS_TIMEUNITS}
HoursPerDay = 24;
MinsPerHour = 60;
SecsPerMin = 60;
MSecsPerSec = 1000;
MinsPerDay = HoursPerDay * MinsPerHour;
SecsPerDay = MinsPerDay * SecsPerMin;
MSecsPerDay = SecsPerDay * MSecsPerSec;
{$ENDIF}
{$IFDEF DOTNET}
// Timeout.Infinite is -1 which violates Cardinal which VCL uses for parameter
// so we are just setting it to this as a hard coded constant until
// the synchro classes and other are all ported directly to portable classes
// (SyncObjs is platform specific)
//Infinite = Timeout.Infinite;
INFINITE = UInt32($FFFFFFFF); { Infinite timeout }
{$ENDIF}
{$IFDEF KYLIX}
NilHandle = 0;
{$ENDIF}
{$IFDEF DELPHI}
NilHandle = 0;
{$ENDIF}
LF = #10;
CR = #13;
// RLebeau: EOL is NOT to be used as a platform-specific line break! Most
// text-based protocols that Indy implements are defined to use CRLF line
// breaks. DO NOT change this! If you need a platform-based line break,
// use sLineBreak instead.
EOL = CR + LF;
//
CHAR0 = #0;
BACKSPACE = #8;
TAB = #9;
CHAR32 = #32;
//Timeout values
IdTimeoutDefault = -1;
IdTimeoutInfinite = -2;
//Fetch Defaults
IdFetchDelimDefault = ' '; {Do not Localize}
IdFetchDeleteDefault = True;
IdFetchCaseSensitiveDefault = True;
IdWhiteSpace = [0..12, 14..32]; {do not localize}
IdHexDigits: array [0..15] of Char = ('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'); {do not localize}
IdOctalDigits: array [0..7] of Char = ('0','1','2','3','4','5','6','7'); {do not localize}
IdHexPrefix = '0x'; {Do not translate}
type
//thread and PID stuff
{$IFDEF DOTNET}
TIdPID = UInt32;
TIdThreadId = UInt32;
TIdThreadHandle = System.Threading.Thread;
{$IFDEF DOTNETDISTRO}
TIdThreadPriority = System.Threading.ThreadPriority;
{$ELSE}
TIdThreadPriority = TThreadPriority;
{$ENDIF}
{$ENDIF}
{$IFDEF UNIX}
{$IFDEF KYLIXCOMPAT}
TIdPID = Int32;
TIdThreadId = Int32;
{$IFDEF FPC}
TIdThreadHandle = TThreadID;
{$ELSE}
TIdThreadHandle = UInt32;
{$ENDIF}
{$IFDEF INT_THREAD_PRIORITY}
TIdThreadPriority = -20..19;
{$ELSE}
TIdThreadPriority = TThreadPriority;
{$ENDIF}
{$ENDIF}
{$IFDEF USE_BASEUNIX}
TIdPID = TPid;
TIdThreadId = TThreadId;
TIdThreadHandle = TIdThreadId;
TIdThreadPriority = TThreadPriority;
{$ENDIF}
{$IFDEF USE_VCL_POSIX}
TIdPID = pid_t;
TIdThreadId = NativeUInt;
TIdThreadHandle = NativeUInt;
{$IFDEF INT_THREAD_PRIORITY}
TIdThreadPriority = -20..19;
{$ELSE}
TIdThreadPriority = TThreadPriority;
{$ENDIF}
{$ENDIF}
{$ENDIF}
{$IFDEF WINDOWS}
TIdPID = UInt32;
TIdThreadId = UInt32;
TIdThreadHandle = THandle;
{$I IdSymbolPlatformOff.inc}
TIdThreadPriority = TThreadPriority;
{$I IdSymbolPlatformOn.inc}
{$ENDIF}
TIdTicks = UInt64;
{$IFDEF INT_THREAD_PRIORITY}
const
// approximate values, its finer grained on Linux
tpIdle = 19;
tpLowest = 12;
tpLower = 6;
tpNormal = 0;
tpHigher = -7;
tpHighest = -13;
tpTimeCritical = -20;
{$ENDIF}
{CH tpIdLowest = tpLowest; }
{CH tpIdBelowNormal = tpLower; }
{CH tpIdNormal = tpNormal; }
{CH tpIdAboveNormal = tpHigher; }
{CH tpIdHighest = tpHighest; }
//end thread stuff
const
//leave this as zero. It's significant in many socket calls that specify ports
DEF_PORT_ANY = 0;
type
{$IFDEF DOTNET}
TIdUnicodeString = System.String;
{$ELSE}
{$IFDEF HAS_UnicodeString}
TIdUnicodeString = UnicodeString;
{$ELSE}
TIdUnicodeString = WideString;
// RP 9/12/2014: Synopse just released a unit that patches the System unit
// in pre-Unicode versions of Delphi to redirect WideString memory management
// to the RTL's memory manager (FastMM, etc) instead of the Win32 COM API!
//
// http://blog.synopse.info/post/2014/09/12/Faster-WideString-process-for-good-old-non-Unicode-Delphi-6-2007
// https://github.com/synopse/mORMot/blob/master/SynFastWideString.pas
//
// We should consider providing an optional setting to enable that patch
// so we can get a performance boost for Unicode-enabled code that uses
// TIdUnicodeString...
{$ENDIF}
{$ENDIF}
// the Delphi next-gen compiler eliminates AnsiString/AnsiChar/PAnsiChar,
// but we still need to deal with Ansi data. Unfortunately, the compiler
// won't let us use its secret _AnsiChr types either, so we have to use
// Byte instead unless we can find a better solution...
{$IFDEF HAS_AnsiChar}
TIdAnsiChar = AnsiChar;
{$ELSE}
TIdAnsiChar = Byte;
{$ENDIF}
{$IFDEF HAS_PAnsiChar}
PIdAnsiChar = PAnsiChar;
{$ELSE}
{$IFDEF HAS_MarshaledAString}
PIdAnsiChar = MarshaledAString;
{$ELSE}
PIdAnsiChar = PByte;
{$ENDIF}
{$ENDIF}
{$IFDEF HAS_PPAnsiChar}
PPIdAnsiChar = PPAnsiChar;
{$ELSE}
PPIdAnsiChar = ^PIdAnsiChar;
{$ENDIF}
{$IFDEF STRING_IS_UNICODE}
TIdWideChar = Char;
PIdWideChar = PChar;
{$ELSE}
TIdWideChar = WideChar;
PIdWideChar = PWideChar;
{$ENDIF}
{$IFDEF WINDOWS}
// .NET and Delphi 2009+ support UNICODE strings natively!
//
// FreePascal 2.4.0+ supports UnicodeString, but does not map its native
// String type to UnicodeString except when {$MODE DelphiUnicode} or
// {$MODESWITCH UnicodeStrings} is enabled. However, UNICODE is not
// defined in that mode yet until FreePascal's RTL has been updated to
// support UnicodeString. STRING_UNICODE_MISMATCH is defined in
// IdCompilerDefines.inc when the compiler's native String/Char types do
// not map to the same types that API functions are expecting based on
// whether UNICODE is defined or not. So we will create special Platform
// typedefs here to help with API function calls when dealing with that
// mismatch...
{$IFDEF UNICODE}
TIdPlatformString = TIdUnicodeString;
TIdPlatformChar = TIdWideChar;
PIdPlatformChar = PIdWideChar;
{$ELSE}
TIdPlatformString = AnsiString;
TIdPlatformChar = TIdAnsiChar;
PIdPlatformChar = PIdAnsiChar;
{$ENDIF}
{$ENDIF}
TIdBytes = array of Byte;
TIdWideChars = array of TIdWideChar;
//NOTE: The code below assumes a 32bit Linux architecture (such as target i386-linux)
{$UNDEF CPU32_OR_KYLIX}
{$IFNDEF DOTNET}
{$IFDEF CPU32}
{$DEFINE CPU32_OR_KYLIX}
{$ENDIF}
{$IFDEF KYLIX}
{$DEFINE CPU32_OR_KYLIX}
{$ENDIF}
{$ENDIF}
// native signed and unsigned integer sized pointer types
{$IFDEF DOTNET}
TIdNativeInt = IntPtr;
TIdNativeUInt = UIntPtr;
{$ELSE}
{$IFDEF HAS_NativeInt}
TIdNativeInt = NativeInt;
{$ELSE}
{$IFDEF CPU32}
TIdNativeInt = Int32;
{$ENDIF}
{$IFDEF CPU64}
TIdNativeInt = Int64;
{$ENDIF}
{$ENDIF}
{$IFDEF HAS_NativeUInt}
TIdNativeUInt = NativeUInt;
{$ELSE}
{$IFDEF CPU32}
TIdNativeUInt = UInt32;
{$ENDIF}
{$IFDEF CPU64}
TIdNativeUInt = UInt64;
{$ENDIF}
{$ENDIF}
{$ENDIF}
{$IFNDEF HAS_PtrInt}
PtrInt = TIdNativeInt;
{$ENDIF}
{$IFNDEF HAS_PtrUInt}
PtrUInt = TIdNativeUInt;
{$ENDIF}
{$IFDEF STREAM_SIZE_64}
TIdStreamSize = Int64;
{$ELSE}
TIdStreamSize = Int32;
{$ENDIF}
{$IFNDEF HAS_SIZE_T}
{$EXTERNALSYM size_t}
size_t = PtrUInt;
{$ENDIF}
{$IFNDEF HAS_PSIZE_T}
{$EXTERNALSYM Psize_t}
Psize_t = ^size_t;
{$ENDIF}
{$IFDEF STRING_IS_IMMUTABLE}
// In .NET and Delphi next-gen, strings are immutable (and zero-indexed), so we
// need to use a StringBuilder whenever we need to modify individual characters
// of a string...
TIdStringBuilder = {$IFDEF DOTNET}System.Text.StringBuilder{$ELSE}TStringBuilder{$ENDIF};
{$ENDIF}
{
Delphi/C++Builder 2009+ have a TEncoding class which mirrors System.Text.Encoding
in .NET, but does not have a TDecoder class which mirrors System.Text.Decoder
in .NET. TEncoding's interface changes from version to version, in some ways
that cause compatibility issues when trying to write portable code, so we will
not rely on it. IIdTextEncoding is our own wrapper so we have control over
text encodings.
This way, Indy can have a unified internal interface for String<->Byte conversions
without using IFDEFs everywhere.
Note: Having the wrapper class use WideString in earlier versions adds extra
overhead to string operations, but this is the only way to ensure that strings
are encoded properly. Later on, perhaps we can optimize the operations when
Ansi-compatible encodings are being used with AnsiString values.
}
{$IFNDEF HAS_IInterface}
IInterface = IUnknown;
{$ENDIF}
IIdTextEncoding = interface(IInterface)
['{FA87FAE5-E3E3-4632-8FCA-2FB786848655}']
function GetByteCount(const AChars: TIdWideChars): Integer; overload;
function GetByteCount(const AChars: TIdWideChars; ACharIndex, ACharCount: Integer): Integer; overload;
{$IFNDEF DOTNET}
function GetByteCount(const AChars: PIdWideChar; ACharCount: Integer): Integer; overload;
{$ENDIF}
function GetByteCount(const AStr: TIdUnicodeString): Integer; overload;
function GetByteCount(const AStr: TIdUnicodeString; ACharIndex, ACharCount: Integer): Integer; overload;
function GetBytes(const AChars: TIdWideChars): TIdBytes; overload;
function GetBytes(const AChars: TIdWideChars; ACharIndex, ACharCount: Integer): TIdBytes; overload;
function GetBytes(const AChars: TIdWideChars; ACharIndex, ACharCount: Integer; var VBytes: TIdBytes; AByteIndex: Integer): Integer; overload;
{$IFNDEF DOTNET}
function GetBytes(const AChars: PIdWideChar; ACharCount: Integer): TIdBytes; overload;
function GetBytes(const AChars: PIdWideChar; ACharCount: Integer; var VBytes: TIdBytes; AByteIndex: Integer): Integer; overload;
function GetBytes(const AChars: PIdWideChar; ACharCount: Integer; ABytes: PByte; AByteCount: Integer): Integer; overload;
{$ENDIF}
function GetBytes(const AStr: TIdUnicodeString): TIdBytes; overload;
function GetBytes(const AStr: TIdUnicodeString; ACharIndex, ACharCount: Integer): TIdBytes; overload;
function GetBytes(const AStr: TIdUnicodeString; ACharIndex, ACharCount: Integer; var VBytes: TIdBytes; AByteIndex: Integer): Integer; overload;
function GetCharCount(const ABytes: TIdBytes): Integer; overload;
function GetCharCount(const ABytes: TIdBytes; AByteIndex, AByteCount: Integer): Integer; overload;
{$IFNDEF DOTNET}
function GetCharCount(const ABytes: PByte; AByteCount: Integer): Integer; overload;
{$ENDIF}
function GetChars(const ABytes: TIdBytes): TIdWideChars; overload;
function GetChars(const ABytes: TIdBytes; AByteIndex, AByteCount: Integer): TIdWideChars; overload;
function GetChars(const ABytes: TIdBytes; AByteIndex, AByteCount: Integer; var VChars: TIdWideChars; ACharIndex: Integer): Integer; overload;
{$IFNDEF DOTNET}
function GetChars(const ABytes: PByte; AByteCount: Integer): TIdWideChars; overload;
function GetChars(const ABytes: PByte; AByteCount: Integer; var VChars: TIdWideChars; ACharIndex: Integer): Integer; overload;
function GetChars(const ABytes: PByte; AByteCount: Integer; AChars: PIdWideChar; ACharCount: Integer): Integer; overload;
{$ENDIF}
function GetIsSingleByte: Boolean;
function GetMaxByteCount(ACharCount: Integer): Integer;
function GetMaxCharCount(AByteCount: Integer): Integer;
function GetPreamble: TIdBytes;
function GetString(const ABytes: TIdBytes): TIdUnicodeString; overload;
function GetString(const ABytes: TIdBytes; AByteIndex, AByteCount: Integer): TIdUnicodeString; overload;
{$IFNDEF DOTNET}
function GetString(const ABytes: PByte; AByteCount: Integer): TIdUnicodeString; overload;
{$ENDIF}
property IsSingleByte: Boolean read GetIsSingleByte;
end;
IdTextEncodingType = (encIndyDefault, encOSDefault, enc8Bit, encASCII, encUTF16BE, encUTF16LE, encUTF7, encUTF8);
function IndyTextEncoding(AType: IdTextEncodingType): IIdTextEncoding; overload;
function IndyTextEncoding(ACodepage: UInt16): IIdTextEncoding; overload;
function IndyTextEncoding(const ACharSet: String): IIdTextEncoding; overload;
{$IFDEF DOTNET}
function IndyTextEncoding(AEncoding: System.Text.Encoding): IIdTextEncoding; overload;
{$ENDIF}
{$IFDEF HAS_TEncoding}
function IndyTextEncoding(AEncoding: TEncoding; AFreeEncoding: Boolean = False): IIdTextEncoding; overload;
{$ENDIF}
function IndyTextEncoding_Default: IIdTextEncoding;
function IndyTextEncoding_OSDefault: IIdTextEncoding;
function IndyTextEncoding_8Bit: IIdTextEncoding;
function IndyTextEncoding_ASCII: IIdTextEncoding;
function IndyTextEncoding_UTF16BE: IIdTextEncoding;
function IndyTextEncoding_UTF16LE: IIdTextEncoding;
function IndyTextEncoding_UTF7: IIdTextEncoding;
function IndyTextEncoding_UTF8: IIdTextEncoding;
// These are for backwards compatibility with past Indy 10 releases
function enDefault: IIdTextEncoding; {$IFDEF HAS_DEPRECATED}deprecated{$IFDEF HAS_DEPRECATED_MSG} 'Use IndyTextEncoding_Default() or a nil IIdTextEncoding pointer'{$ENDIF};{$ENDIF}
{$NODEFINE enDefault}
function en7Bit: IIdTextEncoding; {$IFDEF HAS_DEPRECATED}deprecated{$IFDEF HAS_DEPRECATED_MSG} 'Use IndyTextEncoding_ASCII()'{$ENDIF};{$ENDIF}
{$NODEFINE en7Bit}
function en8Bit: IIdTextEncoding; {$IFDEF HAS_DEPRECATED}deprecated{$IFDEF HAS_DEPRECATED_MSG} 'Use IndyTextEncoding_8Bit()'{$ENDIF};{$ENDIF}
{$NODEFINE en8Bit}
function enUTF8: IIdTextEncoding; {$IFDEF HAS_DEPRECATED}deprecated{$IFDEF HAS_DEPRECATED_MSG} 'Use IndyTextEncoding_UTF8()'{$ENDIF};{$ENDIF}
{$NODEFINE enUTF8}
function Indy8BitEncoding{$IFNDEF DOTNET}(const AOwnedByIndy: Boolean = True){$ENDIF}: IIdTextEncoding; {$IFDEF HAS_DEPRECATED}deprecated{$IFDEF HAS_DEPRECATED_MSG} 'Use IndyTextEncoding_8Bit()'{$ENDIF};{$ENDIF}
function IndyASCIIEncoding{$IFNDEF DOTNET}(const AOwnedByIndy: Boolean = True){$ENDIF}: IIdTextEncoding; {$IFDEF HAS_DEPRECATED}deprecated{$IFDEF HAS_DEPRECATED_MSG} 'Use IndyTextEncoding_ASCII()'{$ENDIF};{$ENDIF}
function IndyUTF16BigEndianEncoding{$IFNDEF DOTNET}(const AOwnedByIndy: Boolean = True){$ENDIF}: IIdTextEncoding; {$IFDEF HAS_DEPRECATED}deprecated{$IFDEF HAS_DEPRECATED_MSG} 'Use IndyTextEncoding_UTF16BE()'{$ENDIF};{$ENDIF}
function IndyUTF16LittleEndianEncoding{$IFNDEF DOTNET}(const AOwnedByIndy: Boolean = True){$ENDIF}: IIdTextEncoding; {$IFDEF HAS_DEPRECATED}deprecated{$IFDEF HAS_DEPRECATED_MSG} 'Use IndyTextEncoding_UTF16LE()'{$ENDIF};{$ENDIF}
function IndyOSDefaultEncoding{$IFNDEF DOTNET}(const AOwnedByIndy: Boolean = True){$ENDIF}: IIdTextEncoding; {$IFDEF HAS_DEPRECATED}deprecated{$IFDEF HAS_DEPRECATED_MSG} 'Use IndyTextEncoding_OSDefault()'{$ENDIF};{$ENDIF}
function IndyUTF7Encoding{$IFNDEF DOTNET}(const AOwnedByIndy: Boolean = True){$ENDIF}: IIdTextEncoding; {$IFDEF HAS_DEPRECATED}deprecated{$IFDEF HAS_DEPRECATED_MSG} 'Use IndyTextEncoding_UTF7()'{$ENDIF};{$ENDIF}
function IndyUTF8Encoding{$IFNDEF DOTNET}(const AOwnedByIndy: Boolean = True){$ENDIF}: IIdTextEncoding; {$IFDEF HAS_DEPRECATED}deprecated{$IFDEF HAS_DEPRECATED_MSG} 'Use IndyTextEncoding_UTF8()'{$ENDIF};{$ENDIF}
(*$HPPEMIT '// These are helper macros to handle differences between C++Builder versions'*)
(*$HPPEMIT '#define TIdTextEncoding_ASCII IndyTextEncoding_ASCII()'*)
(*$HPPEMIT '#define TIdTextEncoding_BigEndianUnicode IndyTextEncoding_UTF16BE()'*)
(*$HPPEMIT '#define TIdTextEncoding_Default IndyTextEncoding_OSDefault()'*)
(*$HPPEMIT '#define TIdTextEncoding_Unicode IndyTextEncoding_UTF16LE()'*)
(*$HPPEMIT '#define TIdTextEncoding_UTF7 IndyTextEncoding_UTF7()'*)
(*$HPPEMIT '#define TIdTextEncoding_UTF8 IndyTextEncoding_UTF8()'*)
(*$HPPEMIT ''*)
(*$HPPEMIT '// These are for backwards compatibility with earlier Indy 10 releases'*)
(*$HPPEMIT '#define enDefault ( ( IIdTextEncoding* )NULL )'*)
(*$HPPEMIT '#define en8Bit IndyTextEncoding_8Bit()'*)
(*$HPPEMIT '#define en7Bit IndyTextEncoding_ASCII()'*)
(*$HPPEMIT '#define enUTF8 IndyTextEncoding_UTF8()'*)
(*$HPPEMIT ''*)
var
{RLebeau: using ASCII by default because most Internet protocols that Indy
implements are based on ASCII specifically, not Ansi. Non-ASCII data has
to be explicitally allowed by RFCs, in which case the caller should not be
using nil IIdTextEncoding objects to begin with...}
GIdDefaultTextEncoding: IdTextEncodingType = encASCII;
{$IFDEF USE_ICONV}
// This indicates whether encOSDefault should map to an OS dependant Ansi
// locale or to ASCII. Defaulting to ASCII for now to maintain compatibility
// with earlier Indy 10 releases...
GIdIconvUseLocaleDependantAnsiEncoding: Boolean = False;
// This indicates whether Iconv should ignore characters that cannot be
// converted. Defaulting to false for now to maintain compatibility with
// earlier Indy 10 releases...
GIdIconvIgnoreIllegalChars: Boolean = False;
// This indicates whether Iconv should transliterate characters that cannot
// be converted. Defaulting to false for now to maintain compatibility with
// earlier Indy 10 releases...
GIdIconvUseTransliteration: Boolean = False;
{$ENDIF}
procedure EnsureEncoding(var VEncoding : IIdTextEncoding; ADefEncoding: IdTextEncodingType = encIndyDefault);
procedure CheckByteEncoding(var VBytes: TIdBytes; ASrcEncoding, ADestEncoding: IIdTextEncoding);
type
TIdAppendFileStream = class(TFileStream)
public
constructor Create(const AFile : String);
end;
TIdReadFileExclusiveStream = class(TFileStream)
public
constructor Create(const AFile : String);
end;
TIdReadFileNonExclusiveStream = class(TFileStream)
public
constructor Create(const AFile : String);
end;
TIdFileCreateStream = class(TFileStream)
public
constructor Create(const AFile : String);
end;
{$IFDEF DOTNET}
{$IFNDEF DOTNET_2_OR_ABOVE}
// dotNET implementation
TWaitResult = (wrSignaled, wrTimeout, wrAbandoned, wrError);
TEvent = class(TObject)
protected
FEvent: WaitHandle;
public
constructor Create(EventAttributes: IntPtr; ManualReset,
InitialState: Boolean; const Name: string = ''); overload;
constructor Create; overload;
destructor Destroy; override;
procedure SetEvent;
procedure ResetEvent;
function WaitFor(Timeout: UInt32): TWaitResult; virtual;
end;
TCriticalSection = class(TObject)
public
procedure Acquire; virtual;
procedure Release; virtual;
function TryEnter: Boolean;
procedure Enter;
procedure Leave;
end;
{$ENDIF}
{$ELSE}
{$IFNDEF NO_REDECLARE}
// TCriticalSection = SyncObjs.TCriticalSection;
{$ENDIF}
{$ENDIF}
TIdLocalEvent = class(TEvent)
public
constructor Create(const AInitialState: Boolean = False;
const AManualReset: Boolean = False); reintroduce;
function WaitForEver: TWaitResult; overload;
end;
// This is here to reduce all the warnings about imports. We may also ifdef
// it to provide a non warning implementatino on this unit too later.
TIdCriticalSection = class(TCriticalSection)
end;
//Only needed for ToBytes(Short) and BytesToShort
{$IFDEF DOTNET}
Short = System.Int16 {$IFDEF HAS_DEPRECATED}deprecated{$IFDEF HAS_DEPRECATED_MSG} 'Use Int16'{$ENDIF}{$ENDIF};
{$ENDIF}
{$IFDEF UNIX}
Short = Int16 {$IFDEF HAS_DEPRECATED}deprecated{$IFDEF HAS_DEPRECATED_MSG} 'Use Int16'{$ENDIF}{$ENDIF};
{$ENDIF}
{$IFNDEF DOTNET}
{$IFNDEF NO_REDECLARE}
PShort = ^Short;
{$ENDIF}
{$ENDIF}
{$IFNDEF DOTNET}
{$IFNDEF HAS_PCardinal}
PCardinal = ^Cardinal;
{$ENDIF}
{$ENDIF}
{$IFDEF HAS_QWord}
{$IFNDEF HAS_PQWord}
PQWord = ^QWord;
{$ENDIF}
{$ENDIF}
{$IFDEF HAS_UInt64}
{$IFNDEF HAS_PUInt64}
PUInt64 = ^UInt64;
{$ENDIF}
{$ELSE}
PUInt64 = {$IFDEF HAS_QWord}PQWord{$ELSE}PInt64{$ENDIF};
{$ENDIF}
//This usually is a property editor exception
EIdCorruptServicesFile = class(EIdException);
EIdEndOfStream = class(EIdException);
EIdInvalidIPv6Address = class(EIdException);
EIdNoEncodingSpecified = class(EIdException);
//This is called whenever there is a failure to retreive the time zone information
EIdFailedToRetreiveTimeZoneInfo = class(EIdException);
TIdPort = UInt16;
//We don't have a native type that can hold an IPv6 address.
{$NODEFINE TIdIPv6Address}
TIdIPv6Address = array [0..7] of UInt16;
// C++ does not allow an array to be returned by a function,
// so wrapping the array in a struct as a workaround...
//
// This is one place where Word is being used instead of UInt16.
// On OSX/iOS, UInt16 is defined in mactypes.h, not in System.hpp!
// don't want to use a bunch of IFDEF's trying to figure out where
// UInt16 is coming from...
//
(*$HPPEMIT 'namespace Idglobal'*)
(*$HPPEMIT '{'*)
(*$HPPEMIT ' struct TIdIPv6Address'*)
(*$HPPEMIT ' {'*)
(*$HPPEMIT ' ::System::Word data[8];'*)
(*$HPPEMIT ' ::System::Word& operator[](int index) { return data[index]; }'*)
(*$HPPEMIT ' const ::System::Word& operator[](int index) const { return data[index]; }'*)
(*$HPPEMIT ' operator const ::System::Word*() const { return data; }'*)
(*$HPPEMIT ' operator ::System::Word*() { return data; }'*)
(*$HPPEMIT ' };'*)
(*$HPPEMIT '}'*)
{This way instead of a boolean for future expansion of other actions}
TIdMaxLineAction = (maException, maSplit);
TIdOSType = (otUnknown, otUnix, otWindows, otDotNet);
//This is for IPv6 support when merged into the core
TIdIPVersion = (Id_IPv4, Id_IPv6);
{$IFNDEF NO_REDECLARE}
{$IFDEF LINUX}
{$IFNDEF VCL_6_OR_ABOVE}
THandle = UInt32; //D6.System
{$ENDIF}
{$ENDIF}
{$ENDIF}
{$IFDEF DOTNET}
THandle = Int32;
{$ELSE}
{$IFDEF WINDOWS}
// THandle = Windows.THandle;
{$ENDIF}
{$ENDIF}
TPosProc = function(const substr, str: String): Integer;
{$IFNDEF DOTNET}
TStrScanProc = function(Str: PChar; Chr: Char): PChar;
{$ENDIF}
TIdReuseSocket = (rsOSDependent, rsTrue, rsFalse);
{$IFNDEF STREAM_SIZE_64}
type
TSeekOrigin = (soBeginning, soCurrent, soEnd);
{$ENDIF}
// TIdBaseStream is defined here to allow TIdMultiPartFormData to be defined
// without any $IFDEFs in the unit IdMultiPartFormData - in accordance with Indy Coding rules
TIdBaseStream = class(TStream)
protected
function IdRead(var VBuffer: TIdBytes; AOffset, ACount: Longint): Longint; virtual; abstract;
function IdWrite(const ABuffer: TIdBytes; AOffset, ACount: Longint): Longint; virtual; abstract;
function IdSeek(const AOffset: Int64; AOrigin: TSeekOrigin): Int64; virtual; abstract;
procedure IdSetSize(ASize: Int64); virtual; abstract;
{$IFDEF DOTNET}
procedure SetSize(ASize: Int64); override;
{$ELSE}
{$IFDEF STREAM_SIZE_64}
procedure SetSize(const NewSize: Int64); override;
{$ELSE}
procedure SetSize(ASize: Integer); override;
{$ENDIF}
{$ENDIF}
public
{$IFDEF DOTNET}
function Read(var VBuffer: array of Byte; AOffset, ACount: Longint): Longint; override;
function Write(const ABuffer: array of Byte; AOffset, ACount: Longint): Longint; override;
function Seek(const AOffset: Int64; AOrigin: TSeekOrigin): Int64; override;
{$ELSE}
function Read(var Buffer; Count: Longint): Longint; override;
function Write(const Buffer; Count: Longint): Longint; override;
{$IFDEF STREAM_SIZE_64}
function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override;
{$ELSE}
function Seek(Offset: Longint; Origin: Word): Longint; override;
{$ENDIF}
{$ENDIF}
end;
TIdCalculateSizeStream = class(TIdBaseStream)
protected
FPosition: Int64;
FSize: Int64;
function IdRead(var VBuffer: TIdBytes; AOffset, ACount: Longint): Longint; override;
function IdWrite(const ABuffer: TIdBytes; AOffset, ACount: Longint): Longint; override;
function IdSeek(const AOffset: Int64; AOrigin: TSeekOrigin): Int64; override;
procedure IdSetSize(ASize: Int64); override;
end;
TIdStreamReadEvent = procedure(var VBuffer: TIdBytes; AOffset, ACount: Longint; var VResult: Longint) of object;
TIdStreamWriteEvent = procedure(const ABuffer: TIdBytes; AOffset, ACount: Longint; var VResult: Longint) of object;
TIdStreamSeekEvent = procedure(const AOffset: Int64; AOrigin: TSeekOrigin; var VPosition: Int64) of object;
TIdStreamSetSizeEvent = procedure(const ANewSize: Int64) of object;
TIdEventStream = class(TIdBaseStream)
protected
FOnRead: TIdStreamReadEvent;
FOnWrite: TIdStreamWriteEvent;
FOnSeek: TIdStreamSeekEvent;
FOnSetSize: TIdStreamSetSizeEvent;
function IdRead(var VBuffer: TIdBytes; AOffset, ACount: Longint): Longint; override;
function IdWrite(const ABuffer: TIdBytes; AOffset, ACount: Longint): Longint; override;
function IdSeek(const AOffset: Int64; AOrigin: TSeekOrigin): Int64; override;
procedure IdSetSize(ASize: Int64); override;
public
property OnRead: TIdStreamReadEvent read FOnRead write FOnRead;
property OnWrite: TIdStreamWriteEvent read FOnWrite write FOnWrite;
property OnSeek: TIdStreamSeekEvent read FOnSeek write FOnSeek;
property OnSetSize: TIdStreamSetSizeEvent read FOnSetSize write FOnSetSize;
end;
{$IFNDEF DOTNET} // what is the .NET equivilent?
TIdMemoryBufferStream = class(TCustomMemoryStream)
public
constructor Create(APtr: Pointer; ASize: TIdNativeInt);
function Write(const Buffer; Count: Longint): Longint; override;
end;
{$ENDIF}
const
{$IFDEF UNIX}
GOSType = otUnix;
GPathDelim = '/'; {do not localize}
INFINITE = UInt32($FFFFFFFF); { Infinite timeout }
{$ENDIF}
{$IFDEF WINDOWS}
GOSType = otWindows;
GPathDelim = '\'; {do not localize}
Infinite = Windows.INFINITE; { redeclare here for use elsewhere without using Windows.pas } // cls modified 1/23/2002
{$ENDIF}
{$IFDEF DOTNET}
GOSType = otDotNet;
GPathDelim = '\'; {do not localize}
// Infinite = ?; { redeclare here for use elsewhere without using Windows.pas } // cls modified 1/23/2002
{$ENDIF}
// S.G. 4/9/2002: IP version general switch for defaults
{$IFDEF IdIPv6}
ID_DEFAULT_IP_VERSION = Id_IPv6;
{$ELSE}
ID_DEFAULT_IP_VERSION = Id_IPv4;
{$ENDIF}
{$IFNDEF HAS_sLineBreak}
{$IFDEF WINDOWS}
sLineBreak = CR + LF;
{$ELSE}
sLineBreak = LF;
{$ENDIF}
{$ENDIF}
//The power constants are for processing IP addresses
//They are powers of 255.
const
POWER_1 = $000000FF;
POWER_2 = $0000FFFF;
POWER_3 = $00FFFFFF;
POWER_4 = $FFFFFFFF;
// utility functions to calculate the usable length of a given buffer.
// If ALength is <0 then the actual Buffer length is returned,
// otherwise the minimum of the two lengths is returned instead.
function IndyLength(const ABuffer: String; const ALength: Integer = -1; const AIndex: Integer = 1): Integer; overload;
function IndyLength(const ABuffer: TIdBytes; const ALength: Integer = -1; const AIndex: Integer = 0): Integer; overload;
function IndyLength(const ABuffer: TStream; const ALength: TIdStreamSize = -1): TIdStreamSize; overload;
function IndyFormat(const AFormat: string; const Args: array of const): string;
function IndyIncludeTrailingPathDelimiter(const S: string): string;
function IndyExcludeTrailingPathDelimiter(const S: string): string;
procedure IndyRaiseLastError;
// This can only be called inside of an 'except' block! This is so that
// Exception.RaiseOuterException() (when available) can capture the current
// exception into the InnerException property of a new Exception that is
// being raised...
procedure IndyRaiseOuterException(AOuterException: Exception);
//You could possibly use the standard StrInt and StrIntDef but these
//also remove spaces from the string using the trim functions.
function IndyStrToInt(const S: string): Integer; overload;
function IndyStrToInt(const S: string; ADefault: Integer): Integer; overload;
function IndyFileAge(const AFileName: string): TDateTime;
function IndyDirectoryExists(const ADirectory: string): Boolean;
//You could possibly use the standard StrToInt and StrToInt64Def
//functions but these also remove spaces using the trim function
function IndyStrToInt64(const S: string; const ADefault: Int64): Int64; overload;
function IndyStrToInt64(const S: string): Int64; overload;
//This converts the string to an Integer or Int64 depending on the bit size TStream uses
function IndyStrToStreamSize(const S: string; const ADefault: TIdStreamSize): TIdStreamSize; overload;
function IndyStrToStreamSize(const S: string): TIdStreamSize; overload;
function AddMSecToTime(const ADateTime: TDateTime; const AMSec: Integer): TDateTime;
// To and From Bytes conversion routines
function ToBytes(const AValue: string; ADestEncoding: IIdTextEncoding = nil
{$IFDEF STRING_IS_ANSI}; ASrcEncoding: IIdTextEncoding = nil{$ENDIF}
): TIdBytes; overload;
function ToBytes(const AValue: string; const ALength: Integer; const AIndex: Integer = 1;
ADestEncoding: IIdTextEncoding = nil
{$IFDEF STRING_IS_ANSI}; ASrcEncoding: IIdTextEncoding = nil{$ENDIF}
): TIdBytes; overload;
function ToBytes(const AValue: Char; ADestEncoding: IIdTextEncoding = nil
{$IFDEF STRING_IS_ANSI}; ASrcEncoding: IIdTextEncoding = nil{$ENDIF}
): TIdBytes; overload;
function ToBytes(const AValue: Int8): TIdBytes; overload;
function ToBytes(const AValue: UInt8): TIdBytes; overload;
function ToBytes(const AValue: Int16): TIdBytes; overload;
function ToBytes(const AValue: UInt16): TIdBytes; overload;
function ToBytes(const AValue: Int32): TIdBytes; overload;
function ToBytes(const AValue: UInt32): TIdBytes; overload;
function ToBytes(const AValue: Int64): TIdBytes; overload;
function ToBytes(const AValue: TIdUInt64): TIdBytes; overload;
function ToBytes(const AValue: TIdBytes; const ASize: Integer; const AIndex: Integer = 0): TIdBytes; overload;
{$IFNDEF DOTNET}
// RLebeau - not using the same "ToBytes" naming convention for RawToBytes()
// in order to prevent ambiquious errors with ToBytes(TIdBytes) above
function RawToBytes(const AValue; const ASize: Integer): TIdBytes;
{$ENDIF}
// The following functions are faster but except that Bytes[] must have enough
// space for at least SizeOf(AValue) bytes.
procedure ToBytesF(var Bytes: TIdBytes; const AValue: Char; ADestEncoding: IIdTextEncoding = nil
{$IFDEF STRING_IS_ANSI}; ASrcEncoding: IIdTextEncoding = nil{$ENDIF}
); overload;
procedure ToBytesF(var Bytes: TIdBytes; const AValue: Int8); overload;
procedure ToBytesF(var Bytes: TIdBytes; const AValue: UInt8); overload;
procedure ToBytesF(var Bytes: TIdBytes; const AValue: Int16); overload;
procedure ToBytesF(var Bytes: TIdBytes; const AValue: UInt16); overload;
procedure ToBytesF(var Bytes: TIdBytes; const AValue: Int32); overload;
procedure ToBytesF(var Bytes: TIdBytes; const AValue: UInt32); overload;
procedure ToBytesF(var Bytes: TIdBytes; const AValue: Int64); overload;
procedure ToBytesF(var Bytes: TIdBytes; const AValue: TIdUInt64); overload;
procedure ToBytesF(var Bytes: TIdBytes; const AValue: TIdBytes; const ASize: Integer; const AIndex: Integer = 0); overload;
{$IFNDEF DOTNET}
// RLebeau - not using the same "ToBytesF" naming convention for RawToBytesF()
// in order to prevent ambiquious errors with ToBytesF(TIdBytes) above
procedure RawToBytesF(var Bytes: TIdBytes; const AValue; const ASize: Integer);
{$ENDIF}
function ToHex(const AValue: TIdBytes; const ACount: Integer = -1; const AIndex: Integer = 0): string; overload;
function ToHex(const AValue: array of UInt32): string; overload; // for IdHash
function BytesToString(const AValue: TIdBytes; AByteEncoding: IIdTextEncoding = nil
{$IFDEF STRING_IS_ANSI}; ADestEncoding: IIdTextEncoding = nil{$ENDIF}
): string; overload;
function BytesToString(const AValue: TIdBytes; const AStartIndex: Integer;
const ALength: Integer = -1; AByteEncoding: IIdTextEncoding = nil
{$IFDEF STRING_IS_ANSI}; ADestEncoding: IIdTextEncoding = nil{$ENDIF}
): string; overload;
// BytesToStringRaw() differs from BytesToString() in that it stores the
// byte octets as-is, whereas BytesToString() may decode character encodings
function BytesToStringRaw(const AValue: TIdBytes): string; overload;
function BytesToStringRaw(const AValue: TIdBytes; const AStartIndex: Integer;
const ALength: Integer = -1): string; overload;
function BytesToChar(const AValue: TIdBytes; const AIndex: Integer = 0;
AByteEncoding: IIdTextEncoding = nil
{$IFDEF STRING_IS_ANSI}; ADestEncoding: IIdTextEncoding = nil{$ENDIF}
): Char; overload;
function BytesToChar(const AValue: TIdBytes; var VChar: Char; const AIndex: Integer = 0;
AByteEncoding: IIdTextEncoding = nil
{$IFDEF STRING_IS_ANSI}; ADestEncoding: IIdTextEncoding = nil{$ENDIF}
): Integer; overload;
function BytesToInt16(const AValue: TIdBytes; const AIndex: Integer = 0): Int16;
function BytesToUInt16(const AValue: TIdBytes; const AIndex : Integer = 0): UInt16;
function BytesToInt32(const AValue: TIdBytes; const AIndex: Integer = 0): Int32;
function BytesToUInt32(const AValue: TIdBytes; const AIndex : Integer = 0): UInt32;
function BytesToInt64(const AValue: TIdBytes; const AIndex: Integer = 0): Int64;
function BytesToUInt64(const AValue: TIdBytes; const AIndex: Integer = 0): TIdUInt64;
function BytesToShort(const AValue: TIdBytes; const AIndex: Integer = 0): Int16; {$IFDEF HAS_DEPRECATED}deprecated{$IFDEF HAS_DEPRECATED_MSG} 'Use BytesToInt16()'{$ENDIF};{$ENDIF}
function BytesToWord(const AValue: TIdBytes; const AIndex : Integer = 0): UInt16; {$IFDEF HAS_DEPRECATED}deprecated{$IFDEF HAS_DEPRECATED_MSG} 'Use BytesToUInt16()'{$ENDIF};{$ENDIF}
function BytesToLongInt(const AValue: TIdBytes; const AIndex: Integer = 0): Int32; {$IFDEF HAS_DEPRECATED}deprecated{$IFDEF HAS_DEPRECATED_MSG} 'Use BytesToInt32()'{$ENDIF};{$ENDIF}
function BytesToLongWord(const AValue: TIdBytes; const AIndex : Integer = 0): UInt32; {$IFDEF HAS_DEPRECATED}deprecated{$IFDEF HAS_DEPRECATED_MSG} 'Use BytesToUInt32()'{$ENDIF};{$ENDIF}
function BytesToIPv4Str(const AValue: TIdBytes; const AIndex: Integer = 0): String;
procedure BytesToIPv6(const AValue: TIdBytes; var VAddress: TIdIPv6Address; const AIndex: Integer = 0);
function BytesToTicks(const AValue: TIdBytes; const AIndex: Integer = 0): TIdTicks;
{$IFNDEF DOTNET}
procedure BytesToRaw(const AValue: TIdBytes; var VBuffer; const ASize: Integer);
{$ENDIF}
// TIdBytes utilities
procedure AppendBytes(var VBytes: TIdBytes; const AToAdd: TIdBytes; const AIndex: Integer = 0; const ALength: Integer = -1);
procedure AppendByte(var VBytes: TIdBytes; const AByte: Byte);
procedure AppendString(var VBytes: TIdBytes; const AStr: String; const ALength: Integer = -1;
ADestEncoding: IIdTextEncoding = nil
{$IFDEF STRING_IS_ANSI}; ASrcEncoding: IIdTextEncoding = nil{$ENDIF}
);
procedure ExpandBytes(var VBytes: TIdBytes; const AIndex: Integer; const ACount: Integer; const AFillByte: Byte = 0);
procedure InsertBytes(var VBytes: TIdBytes; const ADestIndex: Integer; const ASource: TIdBytes; const ASourceIndex: Integer = 0);
procedure InsertByte(var VBytes: TIdBytes; const AByte: Byte; const AIndex: Integer);
procedure RemoveBytes(var VBytes: TIdBytes; const ACount: Integer; const AIndex: Integer = 0);
// Common Streaming routines
function ReadLnFromStream(AStream: TStream; var VLine: String; AMaxLineLength: Integer = -1;
AByteEncoding: IIdTextEncoding = nil
{$IFDEF STRING_IS_ANSI}; ADestEncoding: IIdTextEncoding = nil{$ENDIF}
): Boolean; overload;
function ReadLnFromStream(AStream: TStream; AMaxLineLength: Integer = -1;
AExceptionIfEOF: Boolean = False; AByteEncoding: IIdTextEncoding = nil
{$IFDEF STRING_IS_ANSI}; ADestEncoding: IIdTextEncoding = nil{$ENDIF}
): string; overload;
function ReadStringFromStream(AStream: TStream; ASize: Integer = -1; AByteEncoding: IIdTextEncoding = nil
{$IFDEF STRING_IS_ANSI}; ADestEncoding: IIdTextEncoding = nil{$ENDIF}
): string; overload;
procedure WriteStringToStream(AStream: TStream; const AStr: string; ADestEncoding: IIdTextEncoding
{$IFDEF STRING_IS_ANSI}; ASrcEncoding: IIdTextEncoding = nil{$ENDIF}
); overload;
procedure WriteStringToStream(AStream: TStream; const AStr: string; const ALength: Integer = -1;
const AIndex: Integer = 1; ADestEncoding: IIdTextEncoding = nil
{$IFDEF STRING_IS_ANSI}; ASrcEncoding: IIdTextEncoding = nil{$ENDIF}
); overload;
function ReadCharFromStream(AStream: TStream; var VChar: Char; AByteEncoding: IIdTextEncoding = nil
{$IFDEF STRING_IS_ANSI}; ADestEncoding: IIdTextEncoding = nil{$ENDIF}
): Integer;
function ReadTIdBytesFromStream(const AStream: TStream; var ABytes: TIdBytes;
const Count: TIdStreamSize; const AIndex: Integer = 0): TIdStreamSize;
procedure WriteTIdBytesToStream(const AStream: TStream; const ABytes: TIdBytes;
const ASize: Integer = -1; const AIndex: Integer = 0);
function ByteToHex(const AByte: Byte): string;
function ByteToOctal(const AByte: Byte): string;
function UInt32ToHex(const ALongWord : UInt32) : String;
function LongWordToHex(const ALongWord : UInt32) : String; {$IFDEF HAS_DEPRECATED}deprecated{$IFDEF HAS_DEPRECATED_MSG} 'Use UInt32ToHex()'{$ENDIF};{$ENDIF}
procedure CopyTIdBytes(const ASource: TIdBytes; const ASourceIndex: Integer;
var VDest: TIdBytes; const ADestIndex: Integer; const ALength: Integer);
procedure CopyTIdByteArray(const ASource: array of Byte; const ASourceIndex: Integer;
var VDest: TIdBytes; const ADestIndex: Integer; const ALength: Integer);
procedure CopyTIdChar(const ASource: Char; var VDest: TIdBytes; const ADestIndex: Integer;
ADestEncoding: IIdTextEncoding = nil
{$IFDEF STRING_IS_ANSI}; ASrcEncoding: IIdTextEncoding = nil{$ENDIF}
);
procedure CopyTIdInt16(const ASource: Int16; var VDest: TIdBytes; const ADestIndex: Integer);
procedure CopyTIdUInt16(const ASource: UInt16; var VDest: TIdBytes; const ADestIndex: Integer);
procedure CopyTIdInt32(const ASource: Int32; var VDest: TIdBytes; const ADestIndex: Integer);
procedure CopyTIdUInt32(const ASource: UInt32; var VDest: TIdBytes; const ADestIndex: Integer);
procedure CopyTIdInt64(const ASource: Int64; var VDest: TIdBytes; const ADestIndex: Integer);
procedure CopyTIdUInt64(const ASource: TIdUInt64; var VDest: TIdBytes; const ADestIndex: Integer);
procedure CopyTIdShort(const ASource: Int16; var VDest: TIdBytes; const ADestIndex: Integer); {$IFDEF HAS_DEPRECATED}deprecated{$IFDEF HAS_DEPRECATED_MSG} 'Use CopyTIdInt16()'{$ENDIF};{$ENDIF}
procedure CopyTIdWord(const ASource: UInt16; var VDest: TIdBytes; const ADestIndex: Integer); {$IFDEF HAS_DEPRECATED}deprecated{$IFDEF HAS_DEPRECATED_MSG} 'Use CopyTIdUInt16()'{$ENDIF};{$ENDIF}
procedure CopyTIdLongInt(const ASource: Int32; var VDest: TIdBytes; const ADestIndex: Integer); {$IFDEF HAS_DEPRECATED}deprecated{$IFDEF HAS_DEPRECATED_MSG} 'Use CopyTIdInt32()'{$ENDIF};{$ENDIF}
procedure CopyTIdLongWord(const ASource: UInt32; var VDest: TIdBytes; const ADestIndex: Integer); {$IFDEF HAS_DEPRECATED}deprecated{$IFDEF HAS_DEPRECATED_MSG} 'Use CopyTIdUInt32()'{$ENDIF};{$ENDIF}
procedure CopyTIdIPV6Address(const ASource: TIdIPv6Address; var VDest: TIdBytes; const ADestIndex: Integer);
procedure CopyTIdTicks(const ASource: TIdTicks; var VDest: TIdBytes; const ADestIndex: Integer);
procedure CopyTIdString(const ASource: String; var VDest: TIdBytes; const ADestIndex: Integer;
const ALength: Integer = -1; ADestEncoding: IIdTextEncoding = nil
{$IFDEF STRING_IS_ANSI}; ASrcEncoding: IIdTextEncoding = nil{$ENDIF}
); overload;
procedure CopyTIdString(const ASource: String; const ASourceIndex: Integer;
var VDest: TIdBytes; const ADestIndex: Integer; const ALength: Integer = -1;
ADestEncoding: IIdTextEncoding = nil
{$IFDEF STRING_IS_ANSI}; ASrcEncoding: IIdTextEncoding = nil{$ENDIF}
); overload;
// Need to change prob not to use this set
function CharPosInSet(const AString: string; const ACharPos: Integer; const ASet: String): Integer; {$IFDEF STRING_IS_IMMUTABLE}overload;{$ENDIF}
function CharIsInSet(const AString: string; const ACharPos: Integer; const ASet: String): Boolean; {$IFDEF STRING_IS_IMMUTABLE}overload;{$ENDIF}
function CharIsInEOL(const AString: string; const ACharPos: Integer): Boolean; {$IFDEF STRING_IS_IMMUTABLE}overload;{$ENDIF}
function CharEquals(const AString: string; const ACharPos: Integer; const AValue: Char): Boolean; {$IFDEF STRING_IS_IMMUTABLE}overload;{$ENDIF}
{$IFDEF STRING_IS_IMMUTABLE}
function CharPosInSet(const ASB: TIdStringBuilder; const ACharPos: Integer; const ASet: String): Integer; overload;
function CharIsInSet(const ASB: TIdStringBuilder; const ACharPos: Integer; const ASet: String): Boolean; overload;
function CharIsInEOL(const ASB: TIdStringBuilder; const ACharPos: Integer): Boolean; overload;
function CharEquals(const ASB: TIdStringBuilder; const ACharPos: Integer; const AValue: Char): Boolean; overload;
{$ENDIF}
function ByteIndex(const AByte: Byte; const ABytes: TIdBytes; const AStartIndex: Integer = 0): Integer;
function ByteIdxInSet(const ABytes: TIdBytes; const AIndex: Integer; const ASet: TIdBytes): Integer;
function ByteIsInSet(const ABytes: TIdBytes; const AIndex: Integer; const ASet: TIdBytes): Boolean;
function ByteIsInEOL(const ABytes: TIdBytes; const AIndex: Integer): Boolean;
function CompareDate(const D1, D2: TDateTime): Integer;
function CurrentProcessId: TIdPID;
// RLebeau: the input of these functions must be in GMT
function DateTimeGMTToHttpStr(const GMTValue: TDateTime) : String;
function DateTimeGMTToCookieStr(const GMTValue: TDateTime; const AUseNetscapeFmt: Boolean = True) : String;
function DateTimeGMTToImapStr(const GMTValue: TDateTime) : String;
// RLebeau: the input of these functions must be in local time
function DateTimeToInternetStr(const Value: TDateTime; const AUseGMTStr: Boolean = False) : String; {$IFDEF HAS_DEPRECATED}deprecated{$IFDEF HAS_DEPRECATED_MSG} 'Use LocalDateTimeToGMT()'{$ENDIF};{$ENDIF}
function DateTimeToGmtOffSetStr(ADateTime: TDateTime; const AUseGMTStr: Boolean = False): string; {$IFDEF HAS_DEPRECATED}deprecated{$IFDEF HAS_DEPRECATED_MSG} 'Use UTCOffsetToStr()'{$ENDIF};{$ENDIF}
function LocalDateTimeToHttpStr(const Value: TDateTime) : String;
function LocalDateTimeToCookieStr(const Value: TDateTime; const AUseNetscapeFmt: Boolean = True) : String;
function LocalDateTimeToImapStr(const Value: TDateTime) : String;
function LocalDateTimeToGMT(const Value: TDateTime; const AUseGMTStr: Boolean = False) : String;
procedure DebugOutput(const AText: string);
function Fetch(var AInput: string; const ADelim: string = IdFetchDelimDefault;
const ADelete: Boolean = IdFetchDeleteDefault;
const ACaseSensitive: Boolean = IdFetchCaseSensitiveDefault): string;
function FetchCaseInsensitive(var AInput: string; const ADelim: string = IdFetchDelimDefault;
const ADelete: Boolean = IdFetchDeleteDefault): string;
// TODO: add an index parameter
procedure FillBytes(var VBytes : TIdBytes; const ACount : Integer; const AValue : Byte);
function CurrentThreadId: TIdThreadID;
function GetThreadHandle(AThread: TThread): TIdThreadHandle;
//GetTickDiff required because GetTickCount will wrap (IdICMP uses this)
function GetTickDiff(const AOldTickCount, ANewTickCount: UInt32): UInt32; {$IFDEF HAS_DEPRECATED}deprecated{$IFDEF HAS_DEPRECATED_MSG} 'Use GetTickDiff64()'{$ENDIF};{$ENDIF}
function GetTickDiff64(const AOldTickCount, ANewTickCount: TIdTicks): TIdTicks;
// Most operations that use tick counters will never run anywhere near the
// 49.7 day limit that UInt32 imposes. If an operation really were to
// run that long, use GetElapsedTicks64()...
function GetElapsedTicks(const AOldTickCount: TIdTicks): UInt32;
function GetElapsedTicks64(const AOldTickCount: TIdTicks): TIdTicks;
procedure IdDelete(var s: string; AOffset, ACount: Integer);
procedure IdInsert(const Source: string; var S: string; Index: Integer);
{$IFNDEF DOTNET}
type
// TODO: use "array of Integer" instead?
{$IFDEF HAS_GENERICS_TList}
TIdPortList = TList<Integer>; // TODO: use TIdPort instead?
{$ELSE}
// TODO: flesh out to match TList<Integer> for non-Generics compilers
TIdPortList = TList;
{$ENDIF}
function IdPorts: TIdPortList;
{$ENDIF}
function iif(ATest: Boolean; const ATrue: Integer; const AFalse: Integer): Integer; overload;
function iif(ATest: Boolean; const ATrue: string; const AFalse: string = ''): string; overload; { do not localize }
function iif(ATest: Boolean; const ATrue: Boolean; const AFalse: Boolean): Boolean; overload;
function iif(const AEncoding, ADefEncoding: IIdTextEncoding; ADefEncodingType: IdTextEncodingType = encASCII): IIdTextEncoding; overload;
function InMainThread: Boolean;
function IPv6AddressToStr(const AValue: TIdIPv6Address): string;
//Note that there is NO need for Big Endian byte order functions because
//that's done through HostToNetwork byte order functions.
function HostToLittleEndian(const AValue : UInt16) : UInt16; overload;
function HostToLittleEndian(const AValue : UInt32): UInt32; overload;
function HostToLittleEndian(const AValue : Int32): Int32; overload;
function LittleEndianToHost(const AValue : UInt16) : UInt16; overload;
function LittleEndianToHost(const AValue : UInt32): UInt32; overload;
function LittleEndianToHost(const AValue : Int32): Int32; overload;
procedure WriteMemoryStreamToStream(Src: TMemoryStream; Dest: TStream; Count: TIdStreamSize);
{$IFNDEF DOTNET_EXCLUDE}
function IsCurrentThread(AThread: TThread): boolean;
{$ENDIF}
function IPv4ToUInt32(const AIPAddress: string): UInt32; overload;
function IPv4ToUInt32(const AIPAddress: string; var VErr: Boolean): UInt32; overload;
function IPv4ToDWord(const AIPAddress: string): UInt32; overload; {$IFDEF HAS_DEPRECATED}deprecated{$IFDEF HAS_DEPRECATED_MSG} 'Use IPv4ToUInt32()'{$ENDIF};{$ENDIF}
function IPv4ToDWord(const AIPAddress: string; var VErr: Boolean): UInt32; overload; {$IFDEF HAS_DEPRECATED}deprecated{$IFDEF HAS_DEPRECATED_MSG} 'Use IPv4ToUInt32()'{$ENDIF};{$ENDIF}
function IPv4ToHex(const AIPAddress: string; const ADotted: Boolean = False): string;
function IPv4ToOctal(const AIPAddress: string): string;
procedure IPv6ToIdIPv6Address(const AIPAddress: String; var VAddress: TIdIPv6Address); overload;
procedure IPv6ToIdIPv6Address(const AIPAddress: String; var VAddress: TIdIPv6Address; var VErr : Boolean); overload;
function IsAlpha(const AChar: Char): Boolean; overload;
function IsAlpha(const AString: String; const ALength: Integer = -1; const AIndex: Integer = 1): Boolean; overload;
function IsAlphaNumeric(const AChar: Char): Boolean; overload;
function IsAlphaNumeric(const AString: String; const ALength: Integer = -1; const AIndex: Integer = 1): Boolean; overload;
function IsASCII(const AByte: Byte): Boolean; overload;
function IsASCII(const ABytes: TIdBytes): Boolean; overload;
function IsASCIILDH(const AByte: Byte): Boolean; overload;
function IsASCIILDH(const ABytes: TIdBytes): Boolean; overload;
function IsHexidecimal(const AChar: Char): Boolean; overload;
function IsHexidecimal(const AString: string; const ALength: Integer = -1; const AIndex: Integer = 1): Boolean; overload;
function IsNumeric(const AChar: Char): Boolean; overload;
function IsNumeric(const AString: string): Boolean; overload;
function IsNumeric(const AString: string; const ALength: Integer; const AIndex: Integer = 1): Boolean; overload;
function IsOctal(const AChar: Char): Boolean; overload;
function IsOctal(const AString: string; const ALength: Integer = -1; const AIndex: Integer = 1): Boolean; overload;
{$IFNDEF DOTNET}
function InterlockedExchangeTHandle(var VTarget: THandle; const AValue: THandle): THandle;
function InterlockedCompareExchangePtr(var VTarget: Pointer; const AValue, Compare: Pointer): Pointer;
function InterlockedCompareExchangeObj(var VTarget: TObject; const AValue, Compare: TObject): TObject;
function InterlockedCompareExchangeIntf(var VTarget: IInterface; const AValue, Compare: IInterface): IInterface;
{$ENDIF}
function MakeCanonicalIPv4Address(const AAddr: string): string;
function MakeCanonicalIPv6Address(const AAddr: string): string;
function MakeUInt32IntoIPv4Address(const ADWord: UInt32): string;
function MakeDWordIntoIPv4Address(const ADWord: UInt32): string; {$IFDEF HAS_DEPRECATED}deprecated{$IFDEF HAS_DEPRECATED_MSG} 'Use MakeUInt32IntoIPv4Address()'{$ENDIF};{$ENDIF}
function IndyMin(const AValueOne, AValueTwo: Int64): Int64; overload;
function IndyMin(const AValueOne, AValueTwo: Int32): Int32; overload;
function IndyMin(const AValueOne, AValueTwo: UInt16): UInt16; overload;
function IndyMax(const AValueOne, AValueTwo: Int64): Int64; overload;
function IndyMax(const AValueOne, AValueTwo: Int32): Int32; overload;
function IndyMax(const AValueOne, AValueTwo: UInt16): UInt16; overload;
function IPv4MakeUInt32InRange(const AInt: Int64; const A256Power: Integer): UInt32;
function IPv4MakeLongWordInRange(const AInt: Int64; const A256Power: Integer): UInt32; {$IFDEF HAS_DEPRECATED}deprecated{$IFDEF HAS_DEPRECATED_MSG} 'Use IPv4MakeUInt32InRange()'{$ENDIF};{$ENDIF}
{$IFNDEF DOTNET}
{$IFDEF REGISTER_EXPECTED_MEMORY_LEAK}
function IndyRegisterExpectedMemoryLeak(AAddress: Pointer): Boolean;
{$ENDIF}
{$ENDIF}
{$IFDEF UNIX}
function HackLoad(const ALibName : String; const ALibVersions : array of String) : HMODULE;
{$ENDIF}
{$IFNDEF DOTNET}
function MemoryPos(const ASubStr: string; MemBuff: PChar; MemorySize: Integer): Integer;
{$ENDIF}
function OffsetFromUTC: TDateTime;
function UTCOffsetToStr(const AOffset: TDateTime; const AUseGMTStr: Boolean = False): string;
function PosIdx(const ASubStr, AStr: string; AStartPos: UInt32 = 0): UInt32; //For "ignoreCase" use AnsiUpperCase
function PosInSmallIntArray(const ASearchInt: Int16; const AArray: array of Int16): Integer;
function PosInStrArray(const SearchStr: string; const Contents: array of string; const CaseSensitive: Boolean = True): Integer;
{$IFNDEF DOTNET}
function ServicesFilePath: string;
{$ENDIF}
procedure IndySetThreadPriority(AThread: TThread; const APriority: TIdThreadPriority; const APolicy: Integer = -MaxInt);
procedure SetThreadName(const AName: string; {$IFDEF DOTNET}AThread: System.Threading.Thread = nil{$ELSE}AThreadID: UInt32 = $FFFFFFFF{$ENDIF});
procedure IndySleep(ATime: UInt32);
// TODO: create TIdStringPositionList for non-Nextgen compilers...
{$IFDEF USE_OBJECT_ARC}
type
TIdStringPosition = record
Value: String;
Position: Integer;
constructor Create(const AValue: String; const APosition: Integer);
end;
TIdStringPositionList = TList<TIdStringPosition>;
{$ENDIF}
//For non-Nextgen compilers: Integer(TStrings.Objects[i]) = column position in AData
//For Nextgen compilers: use SplitDelimitedString() if column positions are needed
procedure SplitColumnsNoTrim(const AData: string; AStrings: TStrings; const ADelim: string = ' '); {$IFDEF HAS_DEPRECATED}deprecated{$IFDEF HAS_DEPRECATED_MSG} 'Use SplitDelimitedString()'{$ENDIF};{$ENDIF} {Do not Localize}
procedure SplitColumns(const AData: string; AStrings: TStrings; const ADelim: string = ' '); {$IFDEF HAS_DEPRECATED}deprecated{$IFDEF HAS_DEPRECATED_MSG} 'Use SplitDelimitedString()'{$ENDIF};{$ENDIF} {Do not Localize}
procedure SplitDelimitedString(const AData: string; AStrings: TStrings; ATrim: Boolean; const ADelim: string = ' '{$IFNDEF USE_OBJECT_ARC}; AIncludePositions: Boolean = False{$ENDIF}); {$IFDEF USE_OBJECT_ARC}overload;{$ENDIF} {Do not Localize}
{$IFDEF USE_OBJECT_ARC}
procedure SplitDelimitedString(const AData: string; AStrings: TIdStringPositionList; ATrim: Boolean; const ADelim: string = ' '); overload; {Do not Localize}
{$ENDIF}
function StartsWithACE(const ABytes: TIdBytes): Boolean;
function StringsReplace(const S: String; const OldPattern, NewPattern: array of string): string;
function ReplaceAll(const S, OldPattern, NewPattern: string): string;
function ReplaceOnlyFirst(const S, OldPattern, NewPattern: string): string;
function TextIsSame(const A1, A2: string): Boolean;
function TextStartsWith(const S, SubS: string): Boolean;
function TextEndsWith(const S, SubS: string): Boolean;
function IndyUpperCase(const A1: string): string;
function IndyLowerCase(const A1: string): string;
function IndyCompareStr(const A1: string; const A2: string): Integer;
function Ticks: UInt32; {$IFDEF HAS_DEPRECATED}deprecated{$IFDEF HAS_DEPRECATED_MSG} 'Use Ticks64()'{$ENDIF};{$ENDIF}
function Ticks64: TIdTicks;
procedure ToDo(const AMsg: string);
function TwoByteToUInt16(AByte1, AByte2: Byte): UInt16;
function TwoByteToWord(AByte1, AByte2: Byte): UInt16; {$IFDEF HAS_DEPRECATED}deprecated{$IFDEF HAS_DEPRECATED_MSG} 'Use TwoByteToUInt16()'{$ENDIF};{$ENDIF}
function IndyIndexOf(AStrings: TStrings; const AStr: string; const ACaseSensitive: Boolean = False): Integer;{$IFDEF HAS_TStringList_CaseSensitive} overload;{$ENDIF}
{$IFDEF HAS_TStringList_CaseSensitive}
function IndyIndexOf(AStrings: TStringList; const AStr: string; const ACaseSensitive: Boolean = False): Integer; overload;
{$ENDIF}
function IndyIndexOfName(AStrings: TStrings; const AStr: string; const ACaseSensitive: Boolean = False): Integer;{$IFDEF HAS_TStringList_CaseSensitive} overload;{$ENDIF}
{$IFDEF HAS_TStringList_CaseSensitive}
function IndyIndexOfName(AStrings: TStringList; const AStr: string; const ACaseSensitive: Boolean = False): Integer; overload;
{$ENDIF}
function IndyValueFromIndex(AStrings: TStrings; const AIndex: Integer): String;
{$IFDEF WINDOWS}
function IndyWindowsMajorVersion: Integer;
function IndyWindowsMinorVersion: Integer;
function IndyWindowsBuildNumber: Integer;
function IndyWindowsPlatform: Integer;
function IndyCheckWindowsVersion(const AMajor: Integer; const AMinor: Integer = 0): Boolean;
{$ENDIF}
//For non-Nextgen compilers: IdDisposeAndNil is the same as FreeAndNil()
//For Nextgen compilers: IdDisposeAndNil calls TObject.DisposeOf() to ensure
// the object is freed immediately even if it has active references to it,
// for instance when freeing an Owned component
procedure IdDisposeAndNil(var Obj); {$IFDEF USE_INLINE}inline;{$ENDIF}
//RLebeau: FPC does not provide mach_timebase_info() and mach_absolute_time() yet...
{$IFDEF UNIX}
{$IFDEF DARWIN}
{$IFDEF FPC}
type
TTimebaseInfoData = record
numer: UInt32;
denom: UInt32;
end;
{$ENDIF}
{$ENDIF}
{$ENDIF}
var
{$IFDEF UNIX}
// For linux the user needs to set this variable to be accurate where used (mail, etc)
GOffsetFromUTC: TDateTime = 0;
{$IFDEF DARWIN}
GMachTimeBaseInfo: TTimebaseInfoData;
{$ENDIF}
{$ENDIF}
IndyPos: TPosProc = nil;
{$IFDEF UNIX}
const
{$IFDEF HAS_SharedPrefix}
LIBEXT = '.' + SharedSuffix; {do not localize}
{$ELSE}
{$UNDEF LIBEXT_IS_DYLIB}
{$IFDEF DARWIN}
{$DEFINE LIBEXT_IS_DYLIB}
{$ELSE}
{$IFDEF IOS}
{$IFNDEF CPUARM}
// iOS Simulator
{$DEFINE LIBEXT_IS_DYLIB}
{$ENDIF}
{$ENDIF}
{$ENDIF}
{$IFDEF LIBEXT_IS_DYLIB}
LIBEXT = '.dylib'; {do not localize}
{$ELSE}
LIBEXT = '.so'; {do not localize}
{$ENDIF}
{$ENDIF}
{$ENDIF}
implementation
{$IFDEF UNIX}
{$IFDEF LINUX}
{$DEFINE USE_clock_gettime}
{$IFDEF FPC}
{$linklib rt}
{$ENDIF}
{$ENDIF}
{$IFDEF FREEBSD}
{$DEFINE USE_clock_gettime}
{$ENDIF}
{$ENDIF}
uses
{$IFDEF USE_VCL_POSIX}
Posix.SysSelect,
Posix.SysSocket,
Posix.Time,
Posix.SysTime,
{$ENDIF}
{$IFDEF USE_VCL_POSIX}
{$IFDEF DARWIN}
Macapi.CoreServices,
{$ENDIF}
{$ENDIF}
{$IFDEF REGISTER_EXPECTED_MEMORY_LEAK}
{$IFDEF USE_FASTMM4}FastMM4,{$ENDIF}
{$IFDEF USE_MADEXCEPT}madExcept,{$ENDIF}
{$ENDIF}
{$IFDEF USE_LIBC}Libc,{$ENDIF}
{$IFDEF HAS_UNIT_DateUtils}DateUtils,{$ENDIF}
//do not bring in our IdIconv unit if we are using the libc unit directly.
{$IFDEF USE_ICONV_UNIT}IdIconv, {$ENDIF}
IdResourceStrings,
IdStream,
{$IFDEF DOTNET}
IdStreamNET
{$ELSE}
IdStreamVCL
{$ENDIF}
{$IFDEF HAS_PosEx}
{$IFDEF HAS_UNIT_StrUtils}
,StrUtils
{$ENDIF}
{$ENDIF}
;
{$IFDEF FPC}
{$IFDEF WINCE}
//FreePascal for WindowsCE may not define these.
const
CP_UTF7 = 65000;
CP_UTF8 = 65001;
{$ENDIF}
{$ENDIF}
procedure EnsureEncoding(var VEncoding : IIdTextEncoding; ADefEncoding: IdTextEncodingType = encIndyDefault);
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
if VEncoding = nil then begin
VEncoding := IndyTextEncoding(ADefEncoding);
end;
end;
procedure CheckByteEncoding(var VBytes: TIdBytes; ASrcEncoding, ADestEncoding: IIdTextEncoding);
begin
if ASrcEncoding <> ADestEncoding then begin
VBytes := ADestEncoding.GetBytes(ASrcEncoding.GetChars(VBytes));
end;
end;
{$IFNDEF WINDOWS}
//FreePascal may not define this for non-Windows systems.
//#define MAKEWORD(a, b) ((WORD)(((BYTE)(a)) | ((WORD)((BYTE)(b))) << 8))
function MakeWord(const a, b : Byte) : Word;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Result := Word(a) or (Word(b) shl 8);
end;
{$ENDIF}
{$IFNDEF DOTNET}
var
// TODO: use "array of Integer" instead?
GIdPorts: TIdPortList = nil;
GIdOSDefaultEncoding: IIdTextEncoding = nil;
GId8BitEncoding: IIdTextEncoding = nil;
GIdASCIIEncoding: IIdTextEncoding = nil;
GIdUTF16BigEndianEncoding: IIdTextEncoding = nil;
GIdUTF16LittleEndianEncoding: IIdTextEncoding = nil;
GIdUTF7Encoding: IIdTextEncoding = nil;
GIdUTF8Encoding: IIdTextEncoding = nil;
{$ENDIF}
{ IIdTextEncoding implementations }
{$IFDEF DOTNET}
type
TIdDotNetEncoding = class(TInterfacedObject, IIdTextEncoding)
protected
FEncoding: System.Text.Encoding;
public
constructor Create(AEncoding: System.Text.Encoding); overload;
constructor Create(const ACharset: String); overload;
constructor Create(const ACodepage: UInt16); overload;
function GetByteCount(const AChars: TIdWideChars): Integer; overload;
function GetByteCount(const AChars: TIdWideChars; ACharIndex, ACharCount: Integer): Integer; overload;
function GetByteCount(const AStr: TIdUnicodeString): Integer; overload;
function GetByteCount(const AStr: TIdUnicodeString; ACharIndex, ACharCount: Integer): Integer; overload;
function GetBytes(const AChars: TIdWideChars): TIdBytes; overload;
function GetBytes(const AChars: TIdWideChars; ACharIndex, ACharCount: Integer): TIdBytes; overload;
function GetBytes(const AChars: TIdWideChars; ACharIndex, ACharCount: Integer; var VBytes: TIdBytes; AByteIndex: Integer): Integer; overload;
function GetBytes(const AStr: TIdUnicodeString): TIdBytes; overload;
function GetBytes(const AStr: TIdUnicodeString; ACharIndex, ACharCount: Integer): TIdBytes; overload;
function GetBytes(const AStr: TIdUnicodeString; ACharIndex, ACharCount: Integer; var VBytes: TIdBytes; AByteIndex: Integer): Integer; overload;
function GetCharCount(const ABytes: TIdBytes): Integer; overload;
function GetCharCount(const ABytes: TIdBytes; AByteIndex, AByteCount: Integer): Integer; overload;
function GetChars(const ABytes: TIdBytes): TIdWideChars; overload;
function GetChars(const ABytes: TIdBytes; AByteIndex, AByteCount: Integer): TIdWideChars; overload;
function GetChars(const ABytes: TIdBytes; AByteIndex, AByteCount: Integer; var VChars: TIdWideChars; ACharIndex: Integer): Integer; overload;
function GetIsSingleByte: Boolean;
function GetMaxByteCount(ACharCount: Integer): Integer;
function GetMaxCharCount(AByteCount: Integer): Integer;
function GetPreamble: TIdBytes;
function GetString(const ABytes: TIdBytes): TIdUnicodeString; overload;
function GetString(const ABytes: TIdBytes; AByteIndex, AByteCount: Integer): TIdUnicodeString; overload;
end;
constructor TIdDotNetEncoding.Create(AEncoding: System.Text.Encoding);
begin
inherited Create;
FEncoding := AEncoding;
end;
constructor TIdDotNetEncoding.Create(const ACharset: String);
begin
inherited Create;
FEncoding := System.Text.Encoding.GetEncoding(ACharset);
end;
constructor TIdDotNetEncoding.Create(const ACodepage: UInt16);
begin
inherited Create;
FEncoding := System.Text.Encoding.GetEncoding(ACodepage);
end;
function TIdDotNetEncoding.GetByteCount(const AChars: TIdWideChars): Integer;
begin
Result := FEncoding.GetByteCount(AChars);
end;
function TIdDotNetEncoding.GetByteCount(const AChars: TIdWideChars; ACharIndex, ACharCount: Integer): Integer;
begin
Result := FEncoding.GetByteCount(AChars, ACharIndex, ACharCount);
end;
function TIdDotNetEncoding.GetByteCount(const AStr: TIdUnicodeString): Integer;
begin
Result := FEncoding.GetByteCount(AStr);
end;
function TIdDotNetEncoding.GetByteCount(const AStr: TIdUnicodeString; ACharIndex, ACharCount: Integer): Integer;
begin
Result := FEncoding.GetByteCount(AStr.Substring(ACharIndex-1, ACharCount));
end;
function TIdDotNetEncoding.GetBytes(const AChars: TIdWideChars): TIdBytes;
begin
Result := FEncoding.GetBytes(AChars);
end;
function TIdDotNetEncoding.GetBytes(const AChars: TIdWideChars; ACharIndex, ACharCount: Integer): TIdBytes;
begin
Result := FEncoding.GetBytes(AChars, ACharIndex, ACharCount);
end;
function TIdDotNetEncoding.GetBytes(const AChars: TIdWideChars; ACharIndex, ACharCount: Integer; var VBytes: TIdBytes; AByteIndex: Integer): Integer;
begin
Result := FEncoding.GetBytes(AChars, ACharIndex, ACharCount, VBytes, AByteIndex);
end;
function TIdDotNetEncoding.GetBytes(const AStr: TIdUnicodeString): TIdBytes;
begin
Result := FEncoding.GetBytes(AStr);
end;
function TIdDotNetEncoding.GetBytes(const AStr: TIdUnicodeString; ACharIndex, ACharCount: Integer): TIdBytes;
begin
Result := FEncoding.GetByteCount(AStr.Substring(ACharIndex-1, ACharCount));
end;
function TIdDotNetEncoding.GetBytes(const AStr: TIdUnicodeString; ACharIndex, ACharCount: Integer; var VBytes: TIdBytes; AByteIndex: Integer): Integer;
begin
Result := FEncoding.GetBytes(AStr, ACharIndex-1, ACharCount, VBytes, AByteIndex);
end;
function TIdDotNetEncoding.GetCharCount(const ABytes: TIdBytes): Integer;
begin
Result := FEncoding.GetCharCount(ABytes);
end;
function TIdDotNetEncoding.GetCharCount(const ABytes: TIdBytes; AByteIndex, AByteCount: Integer): Integer;
begin
Result := FEncoding.GetCharCount(ABytes, AByteIndex, AByteCount);
end;
function TIdDotNetEncoding.GetChars(const ABytes: TIdBytes): TIdWideChars;
begin
Result := FEncoding.GetChars(ABytes);
end;
function TIdDotNetEncoding.GetChars(const ABytes: TIdBytes; AByteIndex, AByteCount: Integer): TIdWideChars;
begin
Result := FEncoding.GetChars(ABytes, AByteIndex, AByteCount);
end;
function TIdDotNetEncoding.GetChars(const ABytes: TIdBytes; AByteIndex, AByteCount: Integer; var VChars: TIdWideChars; ACharIndex: Integer): Integer;
begin
Result := FEncoding.GetChars(ABytes, AByteIndex, AByteCount, VChars, ACharIndex);
end;
function TIdDotNetEncoding.GetIsSingleByte: Boolean;
begin
Result := FEncoding.IsSingleByte;
end;
function TIdDotNetEncoding.GetMaxByteCount(ACharCount: Integer): Integer;
begin
Result := FEncoding.GetMaxByteCount(ACharCount);
end;
function TIdDotNetEncoding.GetMaxCharCount(AByteCount: Integer): Integer;
begin
Result := FEncoding.GetMaxCharCount(AByteCount);
end;
function TIdDotNetEncoding.GetPreamble: TIdBytes;
begin
Result := fEncoding.GetPreamble;
end;
function TIdDotNetEncoding.GetString(const ABytes: TIdBytes): TIdUnicodeString;
begin
Result := FEncoding.GetString(ABytes);
end;
function TIdDotNetEncoding.GetString(const ABytes: TIdBytes; AByteIndex, AByteCount: Integer): TIdUnicodeString;
begin
Result := FEncoding.GetString(ABytes, AByteIndex, AByteCount);
end;
{$ELSE}
type
TIdTextEncodingBase = class(TInterfacedObject, IIdTextEncoding)
protected
FIsSingleByte: Boolean;
FMaxCharSize: Integer;
public
function GetByteCount(const AChars: TIdWideChars): Integer; overload;
function GetByteCount(const AChars: TIdWideChars; ACharIndex, ACharCount: Integer): Integer; overload;
function GetByteCount(const AChars: PIdWideChar; ACharCount: Integer): Integer; overload; virtual; abstract;
function GetByteCount(const AStr: TIdUnicodeString): Integer; overload;
function GetByteCount(const AStr: TIdUnicodeString; ACharIndex, ACharCount: Integer): Integer; overload;
function GetBytes(const AChars: TIdWideChars): TIdBytes; overload;
function GetBytes(const AChars: TIdWideChars; ACharIndex, ACharCount: Integer): TIdBytes; overload;
function GetBytes(const AChars: TIdWideChars; ACharIndex, ACharCount: Integer; var VBytes: TIdBytes; AByteIndex: Integer): Integer; overload;
function GetBytes(const AChars: PIdWideChar; ACharCount: Integer): TIdBytes; overload;
function GetBytes(const AChars: PIdWideChar; ACharCount: Integer; var VBytes: TIdBytes; AByteIndex: Integer): Integer; overload;
function GetBytes(const AChars: PIdWideChar; ACharCount: Integer; ABytes: PByte; AByteCount: Integer): Integer; overload; virtual; abstract;
function GetBytes(const AStr: TIdUnicodeString): TIdBytes; overload;
function GetBytes(const AStr: TIdUnicodeString; ACharIndex, ACharCount: Integer): TIdBytes; overload;
function GetBytes(const AStr: TIdUnicodeString; ACharIndex, ACharCount: Integer; var VBytes: TIdBytes; AByteIndex: Integer): Integer; overload;
function GetCharCount(const ABytes: TIdBytes): Integer; overload;
function GetCharCount(const ABytes: TIdBytes; AByteIndex, AByteCount: Integer): Integer; overload;
function GetCharCount(const ABytes: PByte; AByteCount: Integer): Integer; overload; virtual; abstract;
function GetChars(const ABytes: TIdBytes): TIdWideChars; overload;
function GetChars(const ABytes: TIdBytes; AByteIndex, AByteCount: Integer): TIdWideChars; overload;
function GetChars(const ABytes: TIdBytes; AByteIndex, AByteCount: Integer; var VChars: TIdWideChars; ACharIndex: Integer): Integer; overload;
function GetChars(const ABytes: PByte; AByteCount: Integer): TIdWideChars; overload;
function GetChars(const ABytes: PByte; AByteCount: Integer; var VChars: TIdWideChars; ACharIndex: Integer): Integer; overload;
function GetChars(const ABytes: PByte; AByteCount: Integer; AChars: PIdWideChar; ACharCount: Integer): Integer; overload; virtual; abstract;
function GetIsSingleByte: Boolean;
function GetMaxByteCount(ACharCount: Integer): Integer; virtual; abstract;
function GetMaxCharCount(AByteCount: Integer): Integer; virtual; abstract;
function GetPreamble: TIdBytes; virtual;
function GetString(const ABytes: TIdBytes): TIdUnicodeString; overload;
function GetString(const ABytes: TIdBytes; AByteIndex, AByteCount: Integer): TIdUnicodeString; overload;
function GetString(const ABytes: PByte; AByteCount: Integer): TIdUnicodeString; overload;
end;
{$UNDEF SUPPORTS_CODEPAGE_ENCODING}
{$IFNDEF USE_ICONV}
{$IFDEF WINDOWS}
{$DEFINE SUPPORTS_CODEPAGE_ENCODING}
{$ENDIF}
{$IFDEF HAS_LocaleCharsFromUnicode}
{$DEFINE SUPPORTS_CODEPAGE_ENCODING}
{$ENDIF}
{$ENDIF}
TIdMBCSEncoding = class(TIdTextEncodingBase)
private
{$IFDEF USE_ICONV}
FCharSet: String;
{$ELSE}
{$IFDEF SUPPORTS_CODEPAGE_ENCODING}
FCodePage: UInt32;
FMBToWCharFlags: UInt32;
FWCharToMBFlags: UInt32;
{$ENDIF}
{$ENDIF}
public
constructor Create; overload; virtual;
{$IFDEF USE_ICONV}
constructor Create(const CharSet: String); overload; virtual;
{$ELSE}
{$IFDEF SUPPORTS_CODEPAGE_ENCODING}
constructor Create(CodePage: Integer); overload; virtual;
constructor Create(CodePage, MBToWCharFlags, WCharToMBFlags: Integer); overload; virtual;
{$ENDIF}
{$ENDIF}
function GetByteCount(const AChars: PIdWideChar; ACharCount: Integer): Integer; overload; override;
function GetBytes(const AChars: PIdWideChar; ACharCount: Integer; ABytes: PByte; AByteCount: Integer): Integer; overload; override;
function GetCharCount(const ABytes: PByte; AByteCount: Integer): Integer; overload; override;
function GetChars(const ABytes: PByte; AByteCount: Integer; AChars: PIdWideChar; ACharCount: Integer): Integer; overload; override;
function GetMaxByteCount(CharCount: Integer): Integer; override;
function GetMaxCharCount(ByteCount: Integer): Integer; override;
function GetPreamble: TIdBytes; override;
end;
TIdUTF7Encoding = class(TIdMBCSEncoding)
public
constructor Create; override;
function GetByteCount(const AChars: PIdWideChar; ACharCount: Integer): Integer; overload; override;
function GetBytes(const AChars: PIdWideChar; ACharCount: Integer; ABytes: PByte; AByteCount: Integer): Integer; overload; override;
function GetCharCount(const ABytes: PByte; AByteCount: Integer): Integer; overload; override;
function GetChars(const ABytes: PByte; AByteCount: Integer; AChars: PIdWideChar; ACharCount: Integer): Integer; overload; override;
function GetMaxByteCount(CharCount: Integer): Integer; override;
function GetMaxCharCount(ByteCount: Integer): Integer; override;
end;
TIdUTF8Encoding = class(TIdUTF7Encoding)
public
constructor Create; override;
function GetMaxByteCount(CharCount: Integer): Integer; override;
function GetMaxCharCount(ByteCount: Integer): Integer; override;
function GetPreamble: TIdBytes; override;
end;
TIdUTF16LittleEndianEncoding = class(TIdTextEncodingBase)
public
constructor Create; virtual;
function GetByteCount(const AChars: PIdWideChar; ACharCount: Integer): Integer; overload; override;
function GetBytes(const AChars: PIdWideChar; ACharCount: Integer; ABytes: PByte; AByteCount: Integer): Integer; overload; override;
function GetCharCount(const ABytes: PByte; AByteCount: Integer): Integer; overload; override;
function GetChars(const ABytes: PByte; AByteCount: Integer; AChars: PIdWideChar; ACharCount: Integer): Integer; overload; override;
function GetMaxByteCount(CharCount: Integer): Integer; override;
function GetMaxCharCount(ByteCount: Integer): Integer; override;
function GetPreamble: TIdBytes; override;
end;
TIdUTF16BigEndianEncoding = class(TIdUTF16LittleEndianEncoding)
public
function GetBytes(const AChars: PIdWideChar; ACharCount: Integer; ABytes: PByte; AByteCount: Integer): Integer; overload; override;
function GetChars(const ABytes: PByte; AByteCount: Integer; AChars: PIdWideChar; ACharCount: Integer): Integer; overload; override;
function GetPreamble: TIdBytes; override;
end;
TIdASCIIEncoding = class(TIdTextEncodingBase)
public
constructor Create; virtual;
function GetByteCount(const AChars: PIdWideChar; ACharCount: Integer): Integer; override;
function GetBytes(const AChars: PIdWideChar; ACharCount: Integer; ABytes: PByte; AByteCount: Integer): Integer; override;
function GetCharCount(const ABytes: PByte; AByteCount: Integer): Integer; override;
function GetChars(const ABytes: PByte; AByteCount: Integer; AChars: PIdWideChar; ACharCount: Integer): Integer; override;
function GetMaxByteCount(ACharCount: Integer): Integer; override;
function GetMaxCharCount(AByteCount: Integer): Integer; override;
end;
TId8BitEncoding = class(TIdTextEncodingBase)
public
constructor Create; virtual;
function GetByteCount(const AChars: PIdWideChar; ACharCount: Integer): Integer; override;
function GetBytes(const AChars: PIdWideChar; ACharCount: Integer; ABytes: PByte; AByteCount: Integer): Integer; override;
function GetCharCount(const ABytes: PByte; AByteCount: Integer): Integer; override;
function GetChars(const ABytes: PByte; AByteCount: Integer; AChars: PIdWideChar; ACharCount: Integer): Integer; override;
function GetMaxByteCount(ACharCount: Integer): Integer; override;
function GetMaxCharCount(AByteCount: Integer): Integer; override;
end;
{$IFDEF HAS_TEncoding}
TIdVCLEncoding = class(TIdTextEncodingBase)
protected
FEncoding: TEncoding;
FFreeEncoding: Boolean;
public
constructor Create(AEncoding: TEncoding; AFreeEncoding: Boolean); overload;
{$IFDEF HAS_TEncoding_GetEncoding_ByEncodingName}
constructor Create(const ACharset: String); overload;
{$ENDIF}
constructor Create(const ACodepage: UInt16); overload;
destructor Destroy; override;
function GetByteCount(const AChars: PIdWideChar; ACharCount: Integer): Integer; override;
function GetBytes(const AChars: PIdWideChar; ACharCount: Integer; ABytes: PByte; AByteCount: Integer): Integer; override;
function GetCharCount(const ABytes: PByte; AByteCount: Integer): Integer; override;
function GetChars(const ABytes: PByte; AByteCount: Integer; AChars: PIdWideChar; ACharCount: Integer): Integer; override;
function GetMaxByteCount(ACharCount: Integer): Integer; override;
function GetMaxCharCount(AByteCount: Integer): Integer; override;
end;
{$ENDIF}
{ TIdTextEncodingBase }
function ValidateChars(const AChars: TIdWideChars; ACharIndex, ACharCount: Integer): PIdWideChar;
var
Len: Integer;
begin
Len := Length(AChars);
if (ACharIndex < 0) or (ACharIndex >= Len) then begin
raise Exception.CreateResFmt(PResStringRec(@RSCharIndexOutOfBounds), [ACharIndex]);
end;
if ACharCount < 0 then begin
raise Exception.CreateResFmt(PResStringRec(@RSInvalidCharCount), [ACharCount]);
end;
if (Len - ACharIndex) < ACharCount then begin
raise Exception.CreateResFmt(PResStringRec(@RSInvalidCharCount), [ACharCount]);
end;
if ACharCount > 0 then begin
Result := @AChars[ACharIndex];
end else begin
Result := nil;
end;
end;
function ValidateBytes(const ABytes: TIdBytes; AByteIndex, AByteCount: Integer): PByte; overload;
var
Len: Integer;
begin
Len := Length(ABytes);
if (AByteIndex < 0) or (AByteIndex >= Len) then begin
raise Exception.CreateResFmt(PResStringRec(@RSInvalidDestinationIndex), [AByteIndex]);
end;
if (Len - AByteIndex) < AByteCount then begin
raise Exception.CreateRes(PResStringRec(@RSInvalidDestinationArray));
end;
if AByteCount > 0 then begin
Result := @ABytes[AByteIndex];
end else begin
Result := nil;
end;
end;
function ValidateBytes(const ABytes: TIdBytes; AByteIndex, AByteCount, ANeeded: Integer): PByte; overload;
var
Len: Integer;
begin
Len := Length(ABytes);
if (AByteIndex < 0) or (AByteIndex >= Len) then begin
raise Exception.CreateResFmt(PResStringRec(@RSInvalidDestinationIndex), [AByteIndex]);
end;
if (Len - AByteIndex) < ANeeded then begin
raise Exception.CreateRes(PResStringRec(@RSInvalidDestinationArray));
end;
if AByteCount > 0 then begin
Result := @ABytes[AByteIndex];
end else begin
Result := nil;
end;
end;
function ValidateStr(const AStr: TIdUnicodeString; ACharIndex, ACharCount: Integer): PIdWideChar;
begin
if ACharIndex < 1 then begin
raise Exception.CreateResFmt(PResStringRec(@RSCharIndexOutOfBounds), [ACharIndex]);
end;
if ACharCount < 0 then begin
raise Exception.CreateResFmt(PResStringRec(@RSInvalidCharCount), [ACharCount]);
end;
if (Length(AStr) - ACharIndex + 1) < ACharCount then begin
raise Exception.CreateResFmt(PResStringRec(@RSInvalidCharCount), [ACharCount]);
end;
if ACharCount > 0 then begin
Result := @AStr[ACharIndex];
end else begin
Result := nil;
end;
end;
function TIdTextEncodingBase.GetByteCount(const AChars: TIdWideChars): Integer;
begin
if AChars <> nil then begin
Result := GetByteCount(PIdWideChar(AChars), Length(AChars));
end else begin
Result := 0;
end;
end;
function TIdTextEncodingBase.GetByteCount(const AChars: TIdWideChars;
ACharIndex, ACharCount: Integer): Integer;
var
LChars: PIdWideChar;
begin
LChars := ValidateChars(AChars, ACharIndex, ACharCount);
if LChars <> nil then begin
Result := GetByteCount(LChars, ACharCount);
end else begin
Result := 0;
end;
end;
function TIdTextEncodingBase.GetByteCount(const AStr: TIdUnicodeString): Integer;
begin
if AStr <> '' then begin
Result := GetByteCount(PIdWideChar(AStr), Length(AStr));
end else begin
Result := 0;
end;
end;
function TIdTextEncodingBase.GetByteCount(const AStr: TIdUnicodeString; ACharIndex, ACharCount: Integer): Integer;
var
LChars: PIdWideChar;
begin
LChars := ValidateStr(AStr, ACharIndex, ACharCount);
if LChars <> nil then begin
Result := GetByteCount(LChars, ACharCount);
end else begin
Result := 0;
end;
end;
function TIdTextEncodingBase.GetBytes(const AChars: TIdWideChars): TIdBytes;
begin
if AChars <> nil then begin
Result := GetBytes(PIdWideChar(AChars), Length(AChars));
end else begin
Result := nil;
end;
end;
function TIdTextEncodingBase.GetBytes(const AChars: TIdWideChars;
ACharIndex, ACharCount: Integer): TIdBytes;
var
Len: Integer;
begin
Result := nil;
Len := GetByteCount(AChars, ACharIndex, ACharCount);
if Len > 0 then begin
SetLength(Result, Len);
GetBytes(@AChars[ACharIndex], ACharCount, PByte(Result), Len);
end;
end;
function TIdTextEncodingBase.GetBytes(const AChars: TIdWideChars;
ACharIndex, ACharCount: Integer; var VBytes: TIdBytes; AByteIndex: Integer): Integer;
begin
Result := GetBytes(
ValidateChars(AChars, ACharIndex, ACharCount),
ACharCount, VBytes, AByteIndex);
end;
function TIdTextEncodingBase.GetBytes(const AChars: PIdWideChar; ACharCount: Integer): TIdBytes;
var
Len: Integer;
begin
Result := nil;
Len := GetByteCount(AChars, ACharCount);
if Len > 0 then begin
SetLength(Result, Len);
GetBytes(AChars, ACharCount, PByte(Result), Len);
end;
end;
function TIdTextEncodingBase.GetBytes(const AChars: PIdWideChar; ACharCount: Integer;
var VBytes: TIdBytes; AByteIndex: Integer): Integer;
var
Len, LByteCount: Integer;
LBytes: PByte;
begin
if (AChars = nil) and (ACharCount <> 0) then begin
raise Exception.CreateRes(PResStringRec(@RSInvalidSourceArray));
end;
if (VBytes = nil) and (ACharCount <> 0) then begin
raise Exception.CreateRes(PResStringRec(@RSInvalidDestinationArray));
end;
if ACharCount < 0 then begin
raise Exception.CreateResFmt(PResStringRec(@RSInvalidCharCount), [ACharCount]);
end;
Len := Length(VBytes);
LByteCount := GetByteCount(AChars, ACharCount);
LBytes := ValidateBytes(VBytes, AByteIndex, Len, LByteCount);
Dec(Len, AByteIndex);
if (ACharCount > 0) and (Len > 0) then begin
Result := GetBytes(AChars, ACharCount, LBytes, LByteCount);
end else begin
Result := 0;
end;
end;
function TIdTextEncodingBase.GetBytes(const AStr: TIdUnicodeString): TIdBytes;
var
Len: Integer;
begin
Result := nil;
Len := GetByteCount(AStr);
if Len > 0 then begin
SetLength(Result, Len);
GetBytes(PIdWideChar(AStr), Length(AStr), PByte(Result), Len);
end;
end;
function TIdTextEncodingBase.GetBytes(const AStr: TIdUnicodeString; ACharIndex, ACharCount: Integer): TIdBytes;
var
Len: Integer;
LChars: PIdWideChar;
begin
Result := nil;
LChars := ValidateStr(AStr, ACharIndex, ACharCount);
if LChars <> nil then begin
Len := GetByteCount(LChars, ACharCount);
if Len > 0 then begin
SetLength(Result, Len);
GetBytes(LChars, ACharCount, PByte(Result), Len);
end;
end;
end;
function TIdTextEncodingBase.GetBytes(const AStr: TIdUnicodeString; ACharIndex, ACharCount: Integer;
var VBytes: TIdBytes; AByteIndex: Integer): Integer;
var
LChars: PIdWideChar;
begin
LChars := ValidateStr(AStr, ACharIndex, ACharCount);
if LChars <> nil then begin
Result := GetBytes(LChars, ACharCount, VBytes, AByteIndex);
end else begin
Result := 0;
end;
end;
function TIdTextEncodingBase.GetCharCount(const ABytes: TIdBytes): Integer;
begin
if ABytes <> nil then begin
Result := GetCharCount(PByte(ABytes), Length(ABytes));
end else begin
Result := 0;
end;
end;
function TIdTextEncodingBase.GetCharCount(const ABytes: TIdBytes; AByteIndex, AByteCount: Integer): Integer;
var
LBytes: PByte;
begin
LBytes := ValidateBytes(ABytes, AByteIndex, AByteCount);
if LBytes <> nil then begin
Result := GetCharCount(LBytes, AByteCount);
end else begin
Result := 0;
end;
end;
function TIdTextEncodingBase.GetChars(const ABytes: TIdBytes): TIdWideChars;
begin
if ABytes <> nil then begin
Result := GetChars(PByte(ABytes), Length(ABytes));
end else begin
Result := nil;
end;
end;
function TIdTextEncodingBase.GetChars(const ABytes: TIdBytes; AByteIndex, AByteCount: Integer): TIdWideChars;
var
Len: Integer;
begin
Result := nil;
Len := GetCharCount(ABytes, AByteIndex, AByteCount);
if Len > 0 then begin
SetLength(Result, Len);
GetChars(@ABytes[AByteIndex], AByteCount, PIdWideChar(Result), Len);
end;
end;
function TIdTextEncodingBase.GetChars(const ABytes: TIdBytes;
AByteIndex, AByteCount: Integer; var VChars: TIdWideChars; ACharIndex: Integer): Integer;
var
LBytes: PByte;
begin
LBytes := ValidateBytes(ABytes, AByteIndex, AByteCount);
if LBytes <> nil then begin
Result := GetChars(LBytes, AByteCount, VChars, ACharIndex);
end else begin
Result := 0;
end;
end;
function TIdTextEncodingBase.GetChars(const ABytes: PByte; AByteCount: Integer): TIdWideChars;
var
Len: Integer;
begin
Len := GetCharCount(ABytes, AByteCount);
if Len > 0 then begin
SetLength(Result, Len);
GetChars(ABytes, AByteCount, PIdWideChar(Result), Len);
end;
end;
function TIdTextEncodingBase.GetChars(const ABytes: PByte; AByteCount: Integer;
var VChars: TIdWideChars; ACharIndex: Integer): Integer;
var
LCharCount: Integer;
begin
if (ABytes = nil) and (AByteCount <> 0) then begin
raise Exception.CreateRes(PResStringRec(@RSInvalidSourceArray));
end;
if AByteCount < 0 then begin
raise Exception.CreateResFmt(PResStringRec(@RSInvalidCharCount), [AByteCount]);
end;
if (ACharIndex < 0) or (ACharIndex > Length(VChars)) then begin
raise Exception.CreateResFmt(PResStringRec(@RSInvalidDestinationIndex), [ACharIndex]);
end;
LCharCount := GetCharCount(ABytes, AByteCount);
if LCharCount > 0 then begin
if (ACharIndex + LCharCount) > Length(VChars) then begin
raise Exception.CreateRes(PResStringRec(@RSInvalidDestinationArray));
end;
Result := GetChars(ABytes, AByteCount, @VChars[ACharIndex], LCharCount);
end else begin
Result := 0;
end;
end;
function TIdTextEncodingBase.GetIsSingleByte: Boolean;
begin
Result := FIsSingleByte;
end;
function TIdTextEncodingBase.GetPreamble: TIdBytes;
begin
SetLength(Result, 0);
end;
function TIdTextEncodingBase.GetString(const ABytes: TIdBytes): TIdUnicodeString;
begin
if ABytes <> nil then begin
Result := GetString(PByte(ABytes), Length(ABytes));
end else begin
Result := '';
end;
end;
function TIdTextEncodingBase.GetString(const ABytes: TIdBytes;
AByteIndex, AByteCount: Integer): TIdUnicodeString;
var
Len: Integer;
begin
Result := '';
Len := GetCharCount(ABytes, AByteIndex, AByteCount);
if Len > 0 then begin
SetLength(Result, Len);
GetChars(@ABytes[AByteIndex], AByteCount, PIdWideChar(Result), Len);
end;
end;
function TIdTextEncodingBase.GetString(const ABytes: PByte; AByteCount: Integer): TIdUnicodeString;
var
Len: Integer;
begin
Result := '';
Len := GetCharCount(ABytes, AByteCount);
if Len > 0 then begin
SetLength(Result, Len);
GetChars(ABytes, AByteCount, PIdWideChar(Result), Len);
end;
end;
{ TIdMBCSEncoding }
constructor TIdMBCSEncoding.Create;
begin
{$IFDEF USE_ICONV}
Create(iif(GIdIconvUseLocaleDependantAnsiEncoding, 'char', 'ASCII')); {do not localize}
{$ELSE}
{$IFDEF SUPPORTS_CODEPAGE_ENCODING}
Create(CP_ACP, 0, 0);
{$ELSE}
ToDo('Constructor of TIdMBCSEncoding class is not implemented for this platform yet'); {do not localize}
{$ENDIF}
{$ENDIF}
end;
{$IFDEF USE_ICONV}
constructor TIdMBCSEncoding.Create(const CharSet: String);
const
// RLebeau: iconv() does not provide a maximum character byte size like
// Microsoft does, so have to determine the max bytes by manually encoding
// an actual Unicode codepoint. We'll encode the largest codepoint that
// UTF-16 supports, U+10FFFF, for now...
//
cValue: array[0..3] of Byte = ({$IFDEF ENDIAN_BIG}$DB, $FF, $DF, $FF{$ELSE}$FF, $DB, $FF, $DF{$ENDIF});
//cValue: array[0..1] of UInt16 = ($DBFF, $DFFF);
begin
inherited Create;
FCharSet := CharSet;
FMaxCharSize := GetByteCount(PIdWideChar(@cValue[0]), 2);
// Not all charsets support all codepoints. For example, ISO-8859-1 does
// not support U+10FFFF. If GetByteCount() fails above, FMaxCharSize gets
// set to 0, preventing any character conversions. So force FMaxCharSize
// to 1 if GetByteCount() fails, until a better solution can be found.
// Maybe loop through the codepoints until we find the largest one that is
// supported by this charset..
if FMaxCharSize = 0 then begin
FMaxCharSize := 1;
end;
FIsSingleByte := (FMaxCharSize = 1);
end;
{$ELSE}
{$IFDEF SUPPORTS_CODEPAGE_ENCODING}
constructor TIdMBCSEncoding.Create(CodePage: Integer);
begin
Create(CodePage, 0, 0);
end;
constructor TIdMBCSEncoding.Create(CodePage, MBToWCharFlags, WCharToMBFlags: Integer);
{$IFNDEF WINDOWS}
const
// RLebeau: have to determine the max bytes by manually encoding an actual
// Unicode codepoint. We'll encode the largest codepoint that UTF-16 supports,
// U+10FFFF, for now...
//
cValue: array[0..1] of UInt16 = ($DBFF, $DFFF);
{$ELSE}
var
LCPInfo: TCPInfo;
LError: Boolean;
{$ENDIF}
begin
inherited Create;
FCodePage := CodePage;
FMBToWCharFlags := MBToWCharFlags;
FWCharToMBFlags := WCharToMBFlags;
{$IFDEF WINDOWS}
LError := not GetCPInfo(FCodePage, LCPInfo);
if LError and (FCodePage = 20127) then begin
// RLebeau: 20127 is the official codepage for ASCII, but not
// all OS versions support that codepage, so fallback to 1252
// or even 437...
FCodePage := 1252;
LError := not GetCPInfo(FCodePage, LCPInfo);
// just in case...
if LError then begin
FCodePage := 437;
LError := not GetCPInfo(FCodePage, LCPInfo);
end;
end;
if LError then begin
raise EIdException.CreateResFmt(PResStringRec(@RSInvalidCodePage), [FCodePage]);
end;
FMaxCharSize := LCPInfo.MaxCharSize;
{$ELSE}
FMaxCharSize := LocaleCharsFromUnicode(FCodePage, FWCharToMBFlags, @cValue[0], 2, nil, 0, nil, nil);
if FMaxCharSize < 1 then begin
raise EIdException.CreateResFmt(@RSInvalidCodePage, [FCodePage]);
end;
// Not all charsets support all codepoints. For example, ISO-8859-1 does
// not support U+10FFFF. If LocaleCharsFromUnicode() fails above,
// FMaxCharSize gets set to 0, preventing any character conversions. So
// force FMaxCharSize to 1 if GetByteCount() fails, until a better solution
// can be found. Maybe loop through the codepoints until we find the largest
// one that is supported by this codepage..
if FMaxCharSize = 0 then begin
FMaxCharSize := 1;
end;
{$ENDIF}
FIsSingleByte := (FMaxCharSize = 1);
end;
{$ENDIF}
{$ENDIF}
{$IFDEF USE_ICONV}
function CreateIconvHandle(const ACharSet: String; AToUTF16: Boolean): iconv_t;
const
// RLebeau: iconv() outputs a UTF-16 BOM if data is converted to the generic
// "UTF-16" charset. We do not want that, so we will use the "UTF-16LE/BE"
// charset explicitally instead so no BOM is outputted. This also saves us
// from having to manually detect the presense of a BOM and strip it out.
//
// TODO: should we be using UTF-16LE or UTF-16BE on big-endian systems?
// Delphi uses UTF-16LE, but what does FreePascal use? Let's err on the
// side of caution until we know otherwise...
//
cUTF16CharSet = {$IFDEF ENDIAN_BIG}'UTF-16BE'{$ELSE}'UTF-16LE'{$ENDIF}; {do not localize}
var
LToCharSet, LFromCharSet, LFlags: String;
{$IFDEF USE_MARSHALLED_PTRS}
M: TMarshaller;
{$ENDIF}
begin
// on some systems, //IGNORE must be specified before //TRANSLIT if they
// are used together, otherwise //IGNORE gets ignored!
LFlags := '';
if GIdIconvIgnoreIllegalChars then begin
LFlags := LFlags + '//IGNORE'; {do not localize}
end;
if GIdIconvUseTransliteration then begin
LFlags := LFlags + '//TRANSLIT'; {do not localize}
end;
if AToUTF16 then begin
LToCharSet := cUTF16CharSet + LFlags; // explicit convert to Ansi
LFromCharSet := ACharSet; // explicit convert to Ansi
end else begin
LToCharSet := ACharSet + LFlags; // explicit convert to Ansi
LFromCharSet := cUTF16CharSet;
end;
Result := iconv_open(
{$IFDEF USE_MARSHALLED_PTRS}
M.AsAnsi(LToCharSet).ToPointer,
M.AsAnsi(LFromCharSet).ToPointer
{$ELSE}
PAnsiChar(
{$IFDEF STRING_IS_ANSI}
LToCharSet
{$ELSE}
AnsiString(LToCharSet) // explicit convert to Ansi
{$ENDIF}
),
PAnsiChar(
{$IFDEF STRING_IS_ANSI}
LFromCharSet
{$ELSE}
AnsiString(LFromCharSet) // explicit convert to Ansi
{$ENDIF}
)
{$ENDIF}
);
if Result = iconv_t(-1) then begin
if LFlags <> '' then begin
raise EIdException.CreateResFmt(@RSInvalidCharSetConvWithFlags, [ACharSet, cUTF16CharSet, LFlags]);
end else begin
raise EIdException.CreateResFmt(@RSInvalidCharSetConv, [ACharSet, cUTF16CharSet]);
end;
end;
end;
function CalcUTF16ByteSize(AChars: PWideChar; ACharCount: Integer): Integer;
var
C: WideChar;
LCount: Integer;
begin
C := AChars^;
if (C >= #$D800) and (C <= #$DFFF) then
begin
Result := 0;
if C > #$DBFF then begin
// invalid high surrogate
Exit;
end;
if ACharCount = 1 then begin
// missing low surrogate
Exit;
end;
Inc(AChars);
C := AChars^;
if (C < #$DC00) or (C > #$DFFF) then begin
// invalid low surrogate
Exit;
end;
LCount := 2;
end else begin
LCount := 1;
end;
Result := LCount * SizeOf(WideChar);
end;
{$ENDIF}
{$IFDEF USE_ICONV}
function DoIconvCharsToBytes(const ACharset: string; AChars: PIdWideChar; ACharCount: Integer;
ABytes: PByte; AByteCount: Integer; ABytesIsTemp: Boolean): Integer;
var
LSrcCharsPtr: PIdWideChar;
LCharsPtr, LBytesPtr: PAnsiChar;
LSrcCharSize, LCharSize, LByteSize: size_t;
LCharsRead, LBytesWritten: Integer;
LIconv: iconv_t;
begin
Result := 0;
if (AChars = nil) or (ACharCount = 0) then begin
Exit;
end;
LIconv := CreateIconvHandle(ACharSet, False);
try
// RLebeau: iconv() does not allow for querying a pre-calculated byte size
// for the input like Microsoft does, so have to determine the max bytes
// by actually encoding the Unicode data to a real buffer. When ABytesIsTemp
// is True, we are encoding to a small local buffer so we don't have to use
// a lot of memory. We also have to encode the input 1 Unicode codepoint at
// a time to avoid iconv() returning an E2BIG error if multiple UTF-16
// sequences were decoded to a length that would exceed the size of the
// local buffer.
//Kylix has an odd definition in iconv. In Kylix, __outbytesleft is defined as a var
//while in FreePascal's libc and our IdIconv units define it as a pSize_t
// reset to initial state
LByteSize := 0;
if iconv(LIconv, nil, nil, nil, {$IFNDEF KYLIX}@{$ENDIF}LByteSize) = size_t(-1) then begin
Exit;
end;
// do the conversion
LSrcCharsPtr := AChars;
repeat
if LSrcCharsPtr <> nil then begin
LSrcCharSize := CalcUTF16ByteSize(LSrcCharsPtr, ACharCount);
if LSrcCharSize = 0 then begin
Result := 0;
Exit;
end;
end else begin
LSrcCharSize := 0;
end;
LCharsPtr := PAnsiChar(LSrcCharsPtr);
LCharSize := LSrcCharSize;
LBytesPtr := PAnsiChar(ABytes);
LByteSize := AByteCount;
if iconv(LIconv, @LCharsPtr, @LCharSize, @LBytesPtr, {$IFNDEF KYLIX}@{$ENDIF}LByteSize) = size_t(-1) then
begin
Exit;
end;
// LByteSize was decremented by the number of bytes stored in the output buffer
LBytesWritten := AByteCount - LByteSize;
Inc(Result, LBytesWritten);
if LSrcCharsPtr = nil then begin
Exit;
end;
if not ABytesIsTemp then begin
Inc(ABytes, LBytesWritten);
Dec(AByteCount, LBytesWritten);
end;
// LCharSize was decremented by the number of bytes read from the input buffer
LCharsRead := (LSrcCharSize-LCharSize) div SizeOf(WideChar);
Inc(LSrcCharsPtr, LCharsRead);
Dec(ACharCount, LCharsRead);
if ACharCount < 1 then
begin
// After all characters are handled, the output buffer has to be flushed
// This is done by running one more iteration, without an input buffer
LSrcCharsPtr := nil;
end;
until False;
finally
iconv_close(LIconv);
end;
end;
{$ENDIF}
function TIdMBCSEncoding.GetByteCount(const AChars: PIdWideChar; ACharCount: Integer): Integer;
{$IFDEF USE_ICONV}
var
LBytes: array[0..3] of Byte;
{$ENDIF}
begin
{$IFDEF USE_ICONV}
Result := DoIconvCharsToBytes(FCharset, AChars, ACharCount, @LBytes[0], Length(LBytes), True);
{$ELSE}
{$IFDEF HAS_LocaleCharsFromUnicode}
Result := LocaleCharsFromUnicode(FCodePage, FWCharToMBFlags, AChars, ACharCount, nil, 0, nil, nil);
{$ELSE}
{$IFDEF WINDOWS}
Result := WideCharToMultiByte(FCodePage, FWCharToMBFlags, AChars, ACharCount, nil, 0, nil, nil);
{$ELSE}
Result := 0;
ToDo('GetByteCount() method of TIdMBCSEncoding class is not implemented for this platform yet'); {do not localize}
{$ENDIF}
{$ENDIF}
{$ENDIF}
end;
function TIdMBCSEncoding.GetBytes(const AChars: PIdWideChar; ACharCount: Integer; ABytes: PByte;
AByteCount: Integer): Integer;
begin
{$IFDEF USE_ICONV}
Assert (ABytes <> nil, 'TIdMBCSEncoding.GetBytes Bytes can not be nil');
Result := DoIconvCharsToBytes(FCharset, AChars, ACharCount, ABytes, AByteCount, False);
{$ELSE}
{$IFDEF HAS_LocaleCharsFromUnicode}
Result := LocaleCharsFromUnicode(FCodePage, FWCharToMBFlags, AChars, ACharCount, {$IFNDEF HAS_PAnsiChar}Pointer{$ELSE}PAnsiChar{$ENDIF}(ABytes), AByteCount, nil, nil);
{$ELSE}
{$IFDEF WINDOWS}
Result := WideCharToMultiByte(FCodePage, FWCharToMBFlags, AChars, ACharCount, PAnsiChar(ABytes), AByteCount, nil, nil);
{$ELSE}
Result := 0;
ToDo('GetBytes() method of TIdMBCSEncoding class is not implemented for this platform yet'); {do not localize}
{$ENDIF}
{$ENDIF}
{$ENDIF}
end;
{$IFDEF USE_ICONV}
function DoIconvBytesToChars(const ACharset: string; const ABytes: PByte; AByteCount: Integer;
AChars: PWideChar; ACharCount: Integer; AMaxCharSize: Integer; ACharsIsTemp: Boolean): Integer;
var
LSrcBytesPtr: PByte;
LBytesPtr, LCharsPtr: PAnsiChar;
LByteSize, LCharsSize: size_t;
I, LDestCharSize, LMaxBytesSize, LBytesRead, LCharsWritten: Integer;
LConverted: Boolean;
LIconv: iconv_t;
begin
Result := 0;
if (ABytes = nil) or (AByteCount = 0) then begin
Exit;
end;
LIconv := CreateIconvHandle(ACharset, True);
try
// RLebeau: iconv() does not allow for querying a pre-calculated character count
// for the input like Microsoft does, so have to determine the max characters
// by actually encoding the Ansi data to a real buffer. If ACharsIsTemp is True
// then we are encoding to a small local buffer so we don't have to use a lot of
// memory. We also have to encode the input 1 Unicode codepoint at a time to
// avoid iconv() returning an E2BIG error if multiple MBCS sequences were decoded
// to a length that would exceed the size of the local buffer.
//Kylix has an odd definition in iconv. In Kylix, __outbytesleft is defined as a var
//while in FreePascal's libc and our IdIconv units define it as a pSize_t
// reset to initial state
LCharsSize := 0;
if iconv(LIconv, nil, nil, nil, {$IFNDEF KYLIX}@{$ENDIF}LCharsSize) = size_t(-1) then
begin
Exit;
end;
// do the conversion
LSrcBytesPtr := ABytes;
repeat
LMaxBytesSize := IndyMin(AByteCount, AMaxCharSize);
LDestCharSize := ACharCount * SizeOf(WideChar);
if LSrcBytesPtr = nil then
begin
LBytesPtr := nil;
LByteSize := 0;
LCharsPtr := PAnsiChar(AChars);
LCharsSize := LDestCharSize;
if iconv(LIconv, @LBytesPtr, @LByteSize, @LCharsPtr, {$IFNDEF KYLIX}@{$ENDIF}LCharsSize) = size_t(-1) then
begin
Result := 0;
end else
begin
// LCharsSize was decremented by the number of bytes stored in the output buffer
Inc(Result, (LDestCharSize-LCharsSize) div SizeOf(WideChar));
end;
Exit;
end;
// TODO: figure out a better way to calculate the number of input bytes
// needed to generate a single UTF-16 output sequence...
LMaxBytesSize := IndyMin(AByteCount, AMaxCharSize);
LConverted := False;
for I := 1 to LMaxBytesSize do
begin
LBytesPtr := PAnsiChar(LSrcBytesPtr);
LByteSize := I;
LCharsPtr := PAnsiChar(AChars);
LCharsSize := LDestCharSize;
if iconv(LIconv, @LBytesPtr, @LByteSize, @LCharsPtr, {$IFNDEF KYLIX}@{$ENDIF}LCharsSize) <> size_t(-1) then
begin
LConverted := True;
// LCharsSize was decremented by the number of bytes stored in the output buffer
LCharsWritten := (LDestCharSize-LCharsSize) div SizeOf(WideChar);
Inc(Result, LCharsWritten);
if LSrcBytesPtr = nil then begin
Exit;
end;
if not ACharsIsTemp then begin
Inc(AChars, LCharsWritten);
Dec(ACharCount, LCharsWritten);
end;
// LByteSize was decremented by the number of bytes read from the input buffer
LBytesRead := I - LByteSize;
Inc(LSrcBytesPtr, LBytesRead);
Dec(AByteCount, LBytesRead);
if AByteCount < 1 then begin
// After all bytes are handled, the output buffer has to be flushed
// This is done by running one more iteration, without an input buffer
LSrcBytesPtr := nil;
end;
Break;
end;
end;
if not LConverted then begin
Result := 0;
Exit;
end;
until False;
finally
iconv_close(LIconv);
end;
end;
{$ENDIF}
function TIdMBCSEncoding.GetCharCount(const ABytes: PByte; AByteCount: Integer): Integer;
{$IFDEF USE_ICONV}
var
LChars: array[0..3] of WideChar;
{$ENDIF}
begin
{$IFDEF USE_ICONV}
Result := DoIconvBytesToChars(FCharSet, ABytes, AByteCount, @LChars[0], Length(LChars), FMaxCharSize, True);
{$ELSE}
{$IFDEF HAS_UnicodeFromLocaleChars}
Result := UnicodeFromLocaleChars(FCodePage, FMBToWCharFlags, {$IFNDEF HAS_PAnsiChar}Pointer{$ELSE}PAnsiChar{$ENDIF}(ABytes), AByteCount, nil, 0);
{$ELSE}
{$IFDEF WINDOWS}
Result := MultiByteToWideChar(FCodePage, FMBToWCharFlags, PAnsiChar(ABytes), AByteCount, nil, 0);
{$ELSE}
Result := 0;
ToDo('GetCharCount() method of TIdMBCSEncoding class is not implemented for this platform yet'); {do not localize}
{$ENDIF}
{$ENDIF}
{$ENDIF}
end;
function TIdMBCSEncoding.GetChars(const ABytes: PByte; AByteCount: Integer; AChars: PWideChar;
ACharCount: Integer): Integer;
begin
{$IFDEF USE_ICONV}
Result := DoIconvBytesToChars(FCharSet, ABytes, AByteCount, AChars, ACharCount, FMaxCharSize, False);
{$ELSE}
{$IFDEF HAS_UnicodeFromLocaleChars}
Result := UnicodeFromLocaleChars(FCodePage, FMBToWCharFlags, {$IFNDEF HAS_PAnsiChar}Pointer{$ELSE}PAnsiChar{$ENDIF}(ABytes), AByteCount, AChars, ACharCount);
{$ELSE}
{$IFDEF WINDOWS}
Result := MultiByteToWideChar(FCodePage, FMBToWCharFlags, PAnsiChar(ABytes), AByteCount, AChars, ACharCount);
{$ELSE}
Result := 0;
ToDo('GetChars() method of TIdMBCSEncoding class is not implemented for this platform yet'); {do not localize}
{$ENDIF}
{$ENDIF}
{$ENDIF}
end;
function TIdMBCSEncoding.GetMaxByteCount(CharCount: Integer): Integer;
begin
Result := (CharCount + 1) * FMaxCharSize;
end;
function TIdMBCSEncoding.GetMaxCharCount(ByteCount: Integer): Integer;
begin
Result := ByteCount;
end;
function TIdMBCSEncoding.GetPreamble: TIdBytes;
begin
{$IFDEF USE_ICONV}
case PosInStrArray(FCharSet, ['utf-8', 'utf-16', 'utf-16le', 'utf-16be'], False) of {do not localize}
0: begin
SetLength(Result, 3);
Result[0] := $EF;
Result[1] := $BB;
Result[2] := $BF;
end;
1, 2: begin
SetLength(Result, 2);
Result[0] := $FF;
Result[1] := $FE;
end;
3: begin
SetLength(Result, 2);
Result[0] := $FE;
Result[1] := $FF;
end;
else
SetLength(Result, 0);
end;
{$ELSE}
{$IFDEF WINDOWS}
case FCodePage of
CP_UTF8: begin
SetLength(Result, 3);
Result[0] := $EF;
Result[1] := $BB;
Result[2] := $BF;
end;
1200: begin
SetLength(Result, 2);
Result[0] := $FF;
Result[1] := $FE;
end;
1201: begin
SetLength(Result, 2);
Result[0] := $FE;
Result[1] := $FF;
end;
else
SetLength(Result, 0);
end;
{$ELSE}
SetLength(Result, 0);
ToDo('GetPreamble() method of TIdMBCSEncoding class is not implemented for this platform yet'); {do not localize}
{$ENDIF}
{$ENDIF}
end;
{ TIdUTF7Encoding }
constructor TIdUTF7Encoding.Create;
begin
{$IFDEF USE_ICONV}
inherited Create('UTF-7'); {do not localize}
{$ELSE}
{$IFDEF SUPPORTS_CODEPAGE_ENCODING}
inherited Create(CP_UTF7);
{$ELSE}
ToDo('Construtor of TIdUTF7Encoding class is not implemented for this platform yet'); {do not localize}
{$ENDIF}
{$ENDIF}
end;
function TIdUTF7Encoding.GetByteCount(const AChars: PIdWideChar; ACharCount: Integer): Integer;
begin
Result := inherited GetByteCount(AChars, ACharCount);
end;
function TIdUTF7Encoding.GetBytes(const AChars: PIdWideChar; ACharCount: Integer;
ABytes: PByte; AByteCount: Integer): Integer;
begin
Result := inherited GetBytes(AChars, ACharCount, ABytes, AByteCount);
end;
function TIdUTF7Encoding.GetCharCount(const ABytes: PByte; AByteCount: Integer): Integer;
begin
Result := inherited GetCharCount(ABytes, AByteCount);
end;
function TIdUTF7Encoding.GetChars(const ABytes: PByte; AByteCount: Integer;
AChars: PIdWideChar; ACharCount: Integer): Integer;
begin
Result := inherited GetChars(ABytes, AByteCount, AChars, ACharCount);
end;
function TIdUTF7Encoding.GetMaxByteCount(CharCount: Integer): Integer;
begin
Result := (CharCount * 3) + 2;
end;
function TIdUTF7Encoding.GetMaxCharCount(ByteCount: Integer): Integer;
begin
Result := ByteCount;
end;
{ TIdUTF8Encoding }
// TODO: implement UTF-8 manually so we don't have to deal with codepage issues...
constructor TIdUTF8Encoding.Create;
begin
{$IFDEF USE_ICONV}
inherited Create('UTF-8'); {do not localize}
{$ELSE}
{$IFDEF SUPPORTS_CODEPAGE_ENCODING}
inherited Create(CP_UTF8, 0, 0);
{$ELSE}
ToDo('Constructor of TIdUTF8Encoding class is not implemented for this platform yet'); {do not localize}
{$ENDIF}
{$ENDIF}
end;
function TIdUTF8Encoding.GetMaxByteCount(CharCount: Integer): Integer;
begin
Result := (CharCount + 1) * 3;
end;
function TIdUTF8Encoding.GetMaxCharCount(ByteCount: Integer): Integer;
begin
Result := ByteCount + 1;
end;
function TIdUTF8Encoding.GetPreamble: TIdBytes;
begin
SetLength(Result, 3);
Result[0] := $EF;
Result[1] := $BB;
Result[2] := $BF;
end;
{ TIdUTF16LittleEndianEncoding }
constructor TIdUTF16LittleEndianEncoding.Create;
begin
inherited Create;
FIsSingleByte := False;
FMaxCharSize := 4;
end;
function TIdUTF16LittleEndianEncoding.GetByteCount(const AChars: PIdWideChar; ACharCount: Integer): Integer;
begin
// TODO: verify UTF-16 sequences
Result := ACharCount * SizeOf(WideChar);
end;
function TIdUTF16LittleEndianEncoding.GetBytes(const AChars: PIdWideChar; ACharCount: Integer;
ABytes: PByte; AByteCount: Integer): Integer;
{$IFDEF ENDIAN_BIG}
var
I: Integer;
LChars: PIdWideChar;
{$ENDIF}
begin
// TODO: verify UTF-16 sequences
{$IFDEF ENDIAN_BIG}
LChars := AChars;
for I := ACharCount - 1 downto 0 do
begin
ABytes^ := Hi(UInt16(LChars^));
Inc(ABytes);
ABytes^ := Lo(UInt16(LChars^));
Inc(ABytes);
Inc(LChars);
end;
Result := ACharCount * SizeOf(WideChar);
{$ELSE}
Result := ACharCount * SizeOf(WideChar);
Move(AChars^, ABytes^, Result);
{$ENDIF}
end;
function TIdUTF16LittleEndianEncoding.GetCharCount(const ABytes: PByte; AByteCount: Integer): Integer;
begin
// TODO: verify UTF-16 sequences
Result := AByteCount div SizeOf(WideChar);
end;
function TIdUTF16LittleEndianEncoding.GetChars(const ABytes: PByte; AByteCount: Integer;
AChars: PIdWideChar; ACharCount: Integer): Integer;
{$IFDEF ENDIAN_BIG}
var
LBytes1, LBytes2: PByte;
I: Integer;
{$ENDIF}
begin
// TODO: verify UTF-16 sequences
{$IFDEF ENDIAN_BIG}
LBytes1 := ABytes;
LBytes2 := ABytes;
Inc(LBytes2);
for I := 0 to ACharCount - 1 do
begin
AChars^ := WideChar(MakeWord(LBytes2^, LBytes1^));
Inc(LBytes1, 2);
Inc(LBytes2, 2);
Inc(AChars);
end;
Result := ACharCount;
{$ELSE}
Result := AByteCount div SizeOf(WideChar);
Move(ABytes^, AChars^, Result * SizeOf(WideChar));
{$ENDIF}
end;
function TIdUTF16LittleEndianEncoding.GetMaxByteCount(CharCount: Integer): Integer;
begin
Result := (CharCount + 1) * 2;
end;
function TIdUTF16LittleEndianEncoding.GetMaxCharCount(ByteCount: Integer): Integer;
begin
Result := (ByteCount div SizeOf(WideChar)) + (ByteCount and 1) + 1;
end;
function TIdUTF16LittleEndianEncoding.GetPreamble: TIdBytes;
begin
SetLength(Result, 2);
Result[0] := $FF;
Result[1] := $FE;
end;
{ TIdUTF16BigEndianEncoding }
function TIdUTF16BigEndianEncoding.GetBytes(const AChars: PIdWideChar; ACharCount: Integer;
ABytes: PByte; AByteCount: Integer): Integer;
{$IFDEF ENDIAN_LITTLE}
var
I: Integer;
P: PIdWideChar;
{$ENDIF}
begin
{$IFDEF ENDIAN_LITTLE}
P := AChars;
for I := ACharCount - 1 downto 0 do
begin
ABytes^ := Hi(UInt16(P^));
Inc(ABytes);
ABytes^ := Lo(UInt16(P^));
Inc(ABytes);
Inc(P);
end;
Result := ACharCount * SizeOf(WideChar);
{$ELSE}
Result := ACharCount * SizeOf(WideChar);
Move(AChars^, ABytes^, Result);
{$ENDIF}
end;
function TIdUTF16BigEndianEncoding.GetChars(const ABytes: PByte; AByteCount: Integer;
AChars: PIdWideChar; ACharCount: Integer): Integer;
{$IFDEF ENDIAN_LITTLE}
var
P1, P2: PByte;
I: Integer;
{$ENDIF}
begin
{$IFDEF ENDIAN_LITTLE}
P1 := ABytes;
P2 := P1;
Inc(P1);
for I := 0 to ACharCount - 1 do
begin
AChars^ := WideChar(MakeWord(P1^, P2^));
Inc(P2, 2);
Inc(P1, 2);
Inc(AChars);
end;
Result := ACharCount;
{$ELSE}
Result := AByteCount div SizeOf(WideChar);
Move(ABytes^, AChars^, Result * SizeOf(WideChar));
{$ENDIF}
end;
function TIdUTF16BigEndianEncoding.GetPreamble: TIdBytes;
begin
SetLength(Result, 2);
Result[0] := $FE;
Result[1] := $FF;
end;
{ TIdASCIIEncoding }
function IsCharsetASCII(const ACharSet: string): Boolean;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
// TODO: when the IdCharsets unit is moved to the System
// package, use CharsetToCodePage() here...
Result := PosInStrArray(ACharSet,
[
'US-ASCII', {do not localize}
'ANSI_X3.4-1968', {do not localize}
'iso-ir-6', {do not localize}
'ANSI_X3.4-1986', {do not localize}
'ISO_646.irv:1991', {do not localize}
'ASCII', {do not localize}
'ISO646-US', {do not localize}
'us', {do not localize}
'IBM367', {do not localize}
'cp367', {do not localize}
'csASCII' {do not localize}
], False) <> -1;
end;
constructor TIdASCIIEncoding.Create;
begin
inherited Create;
FIsSingleByte := True;
FMaxCharSize := 1;
end;
function TIdASCIIEncoding.GetByteCount(const AChars: PIdWideChar; ACharCount: Integer): Integer;
begin
Result := ACharCount;
end;
function TIdASCIIEncoding.GetBytes(const AChars: PIdWideChar; ACharCount: Integer;
ABytes: PByte; AByteCount: Integer): Integer;
var
P: PIdWideChar;
i : Integer;
begin
P := AChars;
Result := IndyMin(ACharCount, AByteCount);
for i := 1 to Result do begin
// replace illegal characters > $7F
if UInt16(P^) > $007F then begin
ABytes^ := Byte(Ord('?'));
end else begin
ABytes^ := Byte(P^);
end;
//advance to next char
Inc(P);
Inc(ABytes);
end;
end;
function TIdASCIIEncoding.GetCharCount(const ABytes: PByte; AByteCount: Integer): Integer;
begin
Result := AByteCount;
end;
function TIdASCIIEncoding.GetChars(const ABytes: PByte; AByteCount: Integer;
AChars: PIdWideChar; ACharCount: Integer): Integer;
var
P: PByte;
i : Integer;
begin
P := ABytes;
Result := IndyMin(ACharCount, AByteCount);
for i := 1 to Result do begin
// This is an invalid byte in the ASCII encoding.
if P^ > $7F then begin
UInt16(AChars^) := $FFFD;
end else begin
UInt16(AChars^) := P^;
end;
//advance to next byte
Inc(AChars);
Inc(P);
end;
end;
function TIdASCIIEncoding.GetMaxByteCount(ACharCount: Integer): Integer;
begin
Result := ACharCount;
end;
function TIdASCIIEncoding.GetMaxCharCount(AByteCount: Integer): Integer;
begin
Result := AByteCount;
end;
{ TId8BitEncoding }
constructor TId8BitEncoding.Create;
begin
inherited Create;
FIsSingleByte := True;
FMaxCharSize := 1;
end;
function TId8BitEncoding.GetByteCount(const AChars: PIdWideChar; ACharCount: Integer): Integer;
begin
Result := ACharCount;
end;
function TId8BitEncoding.GetBytes(const AChars: PIdWideChar; ACharCount: Integer;
ABytes: PByte; AByteCount: Integer): Integer;
var
P: PIdWideChar;
i : Integer;
begin
P := AChars;
Result := IndyMin(ACharCount, AByteCount);
for i := 1 to Result do begin
// replace illegal characters > $FF
if UInt16(P^) > $00FF then begin
ABytes^ := Byte(Ord('?'));
end else begin
ABytes^ := Byte(P^);
end;
//advance to next char
Inc(P);
Inc(ABytes);
end;
end;
function TId8BitEncoding.GetCharCount(const ABytes: PByte; AByteCount: Integer): Integer;
begin
Result := AByteCount;
end;
function TId8BitEncoding.GetChars(const ABytes: PByte; AByteCount: Integer;
AChars: PIdWideChar; ACharCount: Integer): Integer;
var
P: PByte;
i : Integer;
begin
P := ABytes;
Result := IndyMin(ACharCount, AByteCount);
for i := 1 to Result do begin
UInt16(AChars^) := P^;
//advance to next char
Inc(AChars);
Inc(P);
end;
end;
function TId8BitEncoding.GetMaxByteCount(ACharCount: Integer): Integer;
begin
Result := ACharCount;
end;
function TId8BitEncoding.GetMaxCharCount(AByteCount: Integer): Integer;
begin
Result := AByteCount;
end;
{ TIdVCLEncoding }
{$IFDEF HAS_TEncoding}
// RLebeau: this is a hack. The protected members of SysUtils.TEncoding are
// declared as 'STRICT protected', so a regular accessor will not work here.
// Only descendants can call them, so we have to expose our own methods that
// this unit can call, and have them call the inherited methods internally.
type
TEncodingAccess = class(TEncoding)
public
function IndyGetByteCount(Chars: PChar; CharCount: Integer): Integer;
function IndyGetBytes(Chars: PChar; CharCount: Integer; Bytes: PByte; ByteCount: Integer): Integer;
function IndyGetCharCount(Bytes: PByte; ByteCount: Integer): Integer;
function IndyGetChars(Bytes: PByte; ByteCount: Integer; Chars: PChar; CharCount: Integer): Integer;
end;
function TEncodingAccess.IndyGetByteCount(Chars: PChar; CharCount: Integer): Integer;
begin
Result := GetByteCount(Chars, CharCount);
end;
function TEncodingAccess.IndyGetBytes(Chars: PChar; CharCount: Integer; Bytes: PByte; ByteCount: Integer): Integer;
begin
Result := GetBytes(Chars, CharCount, Bytes, ByteCount);
end;
function TEncodingAccess.IndyGetCharCount(Bytes: PByte; ByteCount: Integer): Integer;
begin
Result := GetCharCount(Bytes, ByteCount);
end;
function TEncodingAccess.IndyGetChars(Bytes: PByte; ByteCount: Integer;
Chars: PChar; CharCount: Integer): Integer;
begin
Result := GetChars(Bytes, ByteCount, Chars, CharCount);
end;
constructor TIdVCLEncoding.Create(AEncoding: TEncoding; AFreeEncoding: Boolean);
begin
inherited Create;
FEncoding := AEncoding;
FFreeEncoding := AFreeEncoding and not TEncoding.IsStandardEncoding(AEncoding);
FIsSingleByte := FEncoding.IsSingleByte;
end;
{$IFDEF HAS_TEncoding_GetEncoding_ByEncodingName}
constructor TIdVCLEncoding.Create(const ACharset: String);
begin
Create(TEncoding.GetEncoding(ACharset), True);
end;
{$ENDIF}
constructor TIdVCLEncoding.Create(const ACodepage: UInt16);
begin
Create(TEncoding.GetEncoding(ACodepage), True);
end;
destructor TIdVCLEncoding.Destroy;
begin
if FFreeEncoding then begin
FEncoding.Free;
end;
inherited Destroy;
end;
function TIdVCLEncoding.GetByteCount(const AChars: PIdWideChar; ACharCount: Integer): Integer;
begin
Result := TEncodingAccess(FEncoding).IndyGetByteCount(AChars, ACharCount);
end;
function TIdVCLEncoding.GetBytes(const AChars: PIdWideChar; ACharCount: Integer;
ABytes: PByte; AByteCount: Integer): Integer;
begin
Result := TEncodingAccess(FEncoding).IndyGetBytes(AChars, ACharCount, ABytes, AByteCount);
end;
function TIdVCLEncoding.GetCharCount(const ABytes: PByte; AByteCount: Integer): Integer;
begin
Result := TEncodingAccess(FEncoding).IndyGetCharCount(ABytes, AByteCount);
end;
function TIdVCLEncoding.GetChars(const ABytes: PByte; AByteCount: Integer;
AChars: PIdWideChar; ACharCount: Integer): Integer;
begin
Result := TEncodingAccess(FEncoding).IndyGetChars(ABytes, AByteCount, AChars, ACharCount);
end;
function TIdVCLEncoding.GetMaxByteCount(ACharCount: Integer): Integer;
begin
Result := FEncoding.GetMaxByteCount(ACharCount);
end;
function TIdVCLEncoding.GetMaxCharCount(AByteCount: Integer): Integer;
begin
Result := FEncoding.GetMaxCharCount(AByteCount);
end;
{$ENDIF}
{$ENDIF}
function IndyTextEncoding(AType: IdTextEncodingType): IIdTextEncoding;
begin
case AType of
encIndyDefault: Result := IndyTextEncoding_Default;
// encOSDefault handled further below
enc8Bit: Result := IndyTextEncoding_8Bit;
encASCII: Result := IndyTextEncoding_ASCII;
encUTF16BE: Result := IndyTextEncoding_UTF16BE;
encUTF16LE: Result := IndyTextEncoding_UTF16LE;
encUTF7: Result := IndyTextEncoding_UTF7;
encUTF8: Result := IndyTextEncoding_UTF8;
else
// encOSDefault
Result := IndyTextEncoding_OSDefault;
end;
end;
function IndyTextEncoding(ACodepage: UInt16): IIdTextEncoding;
begin
{$IFDEF DOTNET}
Result := TIdDotNetEncoding.Create(ACodepage);
{$ELSE}
case ACodepage of
20127:
Result := IndyTextEncoding_ASCII;
1200:
Result := IndyTextEncoding_UTF16LE;
1201:
Result := IndyTextEncoding_UTF16BE;
65000:
Result := IndyTextEncoding_UTF7;
65001:
Result := IndyTextEncoding_UTF8;
else
{$IFDEF SUPPORTS_CODEPAGE_ENCODING}
Result := TIdMBCSEncoding.Create(ACodepage);
{$ELSE}
{$IFDEF HAS_TEncoding}
Result := TIdVCLEncoding.Create(ACodepage);
{$ELSE}
Result := nil;
raise EIdException.CreateResFmt(@RSUnsupportedCodePage, [ACodepage]);
{$ENDIF}
{$ENDIF}
end;
{$ENDIF}
end;
function IndyTextEncoding(const ACharSet: String): IIdTextEncoding;
begin
{$IFDEF DOTNET}
Result := TIdDotNetEncoding.Create(ACharSet);
{$ELSE}
// TODO: move IdCharsets unit into the System package so the
// IdGlobalProtocols.CharsetToEncoding() function can be moved
// into this unit...
if IsCharsetASCII(ACharSet) then begin
Result := IndyTextEncoding_ASCII;
end else begin
case PosInStrArray(ACharSet, ['utf-16be', 'utf-16le', 'utf-16', 'utf-7', 'utf-8'], False) of {do not localize}
0: Result := IndyTextEncoding_UTF16BE;
1, 2: Result := IndyTextEncoding_UTF16LE;
3: Result := IndyTextEncoding_UTF7;
4: Result := IndyTextEncoding_UTF8;
else
{$IFDEF USE_ICONV}
Result := TIdMBCSEncoding.Create(ACharSet);
{$ELSE}
{$IFDEF HAS_TEncoding_GetEncoding_ByEncodingName}
Result := TIdVCLEncoding.Create(ACharSet);
{$ELSE}
// TODO: provide a hook that IdGlobalProtocols can assign to so we can call
// CharsetToCodePage() here, at least until CharsetToEncoding() can be moved
// to this unit once IdCharsets has been moved to the System package...
Result := nil;
raise EIdException.CreateResFmt(PResStringRec(@RSUnsupportedCharSet), [ACharSet]);
{$ENDIF}
{$ENDIF}
end;
end;
{$ENDIF}
end;
{$IFDEF DOTNET}
function IndyTextEncoding(AEncoding: System.Text.Encoding): IIdTextEncoding;
begin
Result := TIdDotNetEncoding.Create(AEncoding);
end;
{$ENDIF}
{$IFDEF HAS_TEncoding}
function IndyTextEncoding(AEncoding: TEncoding; AFreeEncoding: Boolean = False): IIdTextEncoding;
begin
Result := TIdVCLEncoding.Create(AEncoding, AFreeEncoding);
end;
{$ENDIF}
function IndyTextEncoding_Default: IIdTextEncoding;
var
LType: IdTextEncodingType;
begin
LType := GIdDefaultTextEncoding;
if LType = encIndyDefault then begin
LType := encASCII;
end;
Result := IndyTextEncoding(LType);
end;
function IndyTextEncoding_OSDefault: IIdTextEncoding;
{$IFNDEF DOTNET}
var
LEncoding: IIdTextEncoding;
{$ENDIF}
begin
if GIdOSDefaultEncoding = nil then begin
{$IFDEF DOTNET}
// TODO: use thread-safe assignment
GIdOSDefaultEncoding := TIdDotNetEncoding.Create(System.Text.Encoding.Default);
{$ELSE}
// TODO: SysUtils.TEncoding.Default uses ANSI on Windows
// but uses UTF-8 on POSIX, so we should do the same...
//LEncoding := {$IFDEF WINDOWS}TIdMBCSEncoding{$ELSE}TIdUTF8Encoding{$ENDIF}.Create;
LEncoding := TIdMBCSEncoding.Create;
if InterlockedCompareExchangeIntf(IInterface(GIdOSDefaultEncoding), LEncoding, nil) <> nil then begin
LEncoding := nil;
end;
{$ENDIF}
end;
Result := GIdOSDefaultEncoding;
end;
function IndyTextEncoding_8Bit: IIdTextEncoding;
{$IFNDEF DOTNET}
var
LEncoding: IIdTextEncoding;
{$ENDIF}
begin
if GId8BitEncoding = nil then begin
{$IFDEF DOTNET}
// We need a charset that converts UTF-16 codeunits in the $00-$FF range
// to/from their numeric values as-is. Was previously using "Windows-1252"
// which does so for most codeunits, however codeunits $80-$9F in
// Windows-1252 map to different codepoints in Unicode, which we don't want.
// "ISO-8859-1" aka "ISO_8859-1:1987" (not to be confused with the older
// "ISO 8859-1" charset), on the other hand, treats codeunits $00-$FF as-is,
// and seems to be just as widely supported as Windows-1252 on most systems,
// so we'll use that for now...
// TODO: use thread-safe assignment
GId8BitEncoding := TIdDotNetEncoding.Create('ISO-8859-1');
{$ELSE}
LEncoding := TId8BitEncoding.Create;
if InterlockedCompareExchangeIntf(IInterface(GId8BitEncoding), LEncoding, nil) <> nil then begin
LEncoding := nil;
end;
{$ENDIF}
end;
Result := GId8BitEncoding;
end;
function IndyTextEncoding_ASCII: IIdTextEncoding;
{$IFNDEF DOTNET}
var
LEncoding: IIdTextEncoding;
{$ENDIF}
begin
if GIdASCIIEncoding = nil then begin
{$IFDEF DOTNET}
// TODO: use thread-safe assignment
GIdASCIIEncoding := TIdDotNetEncoding.Creeate(System.Text.Encoding.ASCII);
{$ELSE}
LEncoding := TIdASCIIEncoding.Create;
if InterlockedCompareExchangeIntf(IInterface(GIdASCIIEncoding), LEncoding, nil) <> nil then begin
LEncoding := nil;
end;
{$ENDIF}
end;
Result := GIdASCIIEncoding;
end;
function IndyTextEncoding_UTF16BE: IIdTextEncoding;
{$IFNDEF DOTNET}
var
LEncoding: IIdTextEncoding;
{$ENDIF}
begin
if GIdUTF16BigEndianEncoding = nil then begin
{$IFDEF DOTNET}
// TODO: use thread-safe assignment
GIdUTF16BigEndianEncoding := TIdDotNetEncoding.Create(System.Text.Encoding.BigEndianUnicode);
{$ELSE}
LEncoding := TIdUTF16BigEndianEncoding.Create;
if InterlockedCompareExchangeIntf(IInterface(GIdUTF16BigEndianEncoding), LEncoding, nil) <> nil then begin
LEncoding := nil;
end;
{$ENDIF}
end;
Result := GIdUTF16BigEndianEncoding;
end;
function IndyTextEncoding_UTF16LE: IIdTextEncoding;
{$IFNDEF DOTNET}
var
LEncoding: IIdTextEncoding;
{$ENDIF}
begin
if GIdUTF16LittleEndianEncoding = nil then begin
{$IFDEF DOTNET}
// TODO: use thread-safe assignment
GIdUTF16LittleEndianEncoding := TIdDotNetEncoding.Create(System.Text.Encoding.Unicode);
{$ELSE}
LEncoding := TIdUTF16LittleEndianEncoding.Create;
if InterlockedCompareExchangeIntf(IInterface(GIdUTF16LittleEndianEncoding), LEncoding, nil) <> nil then begin
LEncoding := nil;
end;
{$ENDIF}
end;
Result := GIdUTF16LittleEndianEncoding;
end;
function IndyTextEncoding_UTF7: IIdTextEncoding;
{$IFNDEF DOTNET}
var
LEncoding: IIdTextEncoding;
{$ENDIF}
begin
if GIdUTF7Encoding = nil then begin
{$IFDEF DOTNET}
// TODO: use thread-safe assignment
GIdUTF7Encoding := TIdDotNetEncoding.Create(System.Text.Encoding.UTF7);
{$ELSE}
LEncoding := TIdUTF7Encoding.Create;
if InterlockedCompareExchangeIntf(IInterface(GIdUTF7Encoding), LEncoding, nil) <> nil then begin
LEncoding := nil;
end;
{$ENDIF}
end;
Result := GIdUTF7Encoding;
end;
function IndyTextEncoding_UTF8: IIdTextEncoding;
{$IFNDEF DOTNET}
var
LEncoding: IIdTextEncoding;
{$ENDIF}
begin
if GIdUTF8Encoding = nil then begin
{$IFDEF DOTNET}
// TODO: use thread-safe assignment
GIdUTF8Encoding := TIdDotNetEncoding.Create(System.Text.Encoding.UTF8);
{$ELSE}
LEncoding := TIdUTF8Encoding.Create;
if InterlockedCompareExchangeIntf(IInterface(GIdUTF8Encoding), LEncoding, nil) <> nil then begin
LEncoding := nil;
end;
{$ENDIF}
end;
Result := GIdUTF8Encoding;
end;
{$I IdDeprecatedImplBugOff.inc}
function enDefault: IIdTextEncoding;
{$I IdDeprecatedImplBugOn.inc}
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Result := nil;
end;
{$I IdDeprecatedImplBugOff.inc}
function en7Bit: IIdTextEncoding;
{$I IdDeprecatedImplBugOn.inc}
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Result := IndyTextEncoding_ASCII;
end;
{$I IdDeprecatedImplBugOff.inc}
function en8Bit: IIdTextEncoding;
{$I IdDeprecatedImplBugOn.inc}
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Result := IndyTextEncoding_8Bit;
end;
{$I IdDeprecatedImplBugOff.inc}
function enUTF8: IIdTextEncoding;
{$I IdDeprecatedImplBugOn.inc}
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Result := IndyTextEncoding_UTF8;
end;
{$I IdDeprecatedImplBugOff.inc}
function Indy8BitEncoding{$IFNDEF DOTNET}(const AOwnedByIndy: Boolean = True){$ENDIF}: IIdTextEncoding;
{$I IdDeprecatedImplBugOn.inc}
begin
{$IFNDEF DOTNET}
if not AOwnedByIndy then begin
Result := TId8BitEncoding.Create;
Exit;
end;
{$ENDIF}
Result := IndyTextEncoding_8Bit;
end;
{$I IdDeprecatedImplBugOff.inc}
function IndyASCIIEncoding{$IFNDEF DOTNET}(const AOwnedByIndy: Boolean = True){$ENDIF}: IIdTextEncoding;
{$I IdDeprecatedImplBugOn.inc}
begin
{$IFNDEF DOTNET}
if not AOwnedByIndy then begin
Result := TIdASCIIEncoding.Create;
Exit;
end;
{$ENDIF}
Result := IndyTextEncoding_ASCII;
end;
{$I IdDeprecatedImplBugOff.inc}
function IndyUTF16BigEndianEncoding{$IFNDEF DOTNET}(const AOwnedByIndy: Boolean = True){$ENDIF}: IIdTextEncoding;
{$I IdDeprecatedImplBugOn.inc}
begin
{$IFNDEF DOTNET}
if not AOwnedByIndy then begin
Result := TIdUTF16BigEndianEncoding.Create;
Exit;
end;
{$ENDIF}
Result := IndyTextEncoding_UTF16BE;
end;
{$I IdDeprecatedImplBugOff.inc}
function IndyUTF16LittleEndianEncoding{$IFNDEF DOTNET}(const AOwnedByIndy: Boolean = True){$ENDIF}: IIdTextEncoding;
{$I IdDeprecatedImplBugOn.inc}
begin
{$IFNDEF DOTNET}
if not AOwnedByIndy then begin
Result := TIdUTF16LittleEndianEncoding.Create;
Exit;
end;
{$ENDIF}
Result := IndyTextEncoding_UTF16LE;
end;
{$I IdDeprecatedImplBugOff.inc}
function IndyOSDefaultEncoding{$IFNDEF DOTNET}(const AOwnedByIndy: Boolean = True){$ENDIF}: IIdTextEncoding;
{$I IdDeprecatedImplBugOn.inc}
begin
{$IFNDEF DOTNET}
if not AOwnedByIndy then begin
// TODO: SysUtils.TEncoding.Default uses ANSI on Windows
// but uses UTF-8 on POSIX, so we should do the same...
//Result := {$IFDEF WINDOWS}TIdMBCSEncoding{$ELSE}TIdUTF8Encoding{$ENDIF}.Create;
Result := TIdMBCSEncoding.Create;
Exit;
end;
{$ENDIF}
Result := IndyTextEncoding_OSDefault;
end;
{$I IdDeprecatedImplBugOff.inc}
function IndyUTF7Encoding{$IFNDEF DOTNET}(const AOwnedByIndy: Boolean = True){$ENDIF}: IIdTextEncoding;
{$I IdDeprecatedImplBugOn.inc}
begin
{$IFNDEF DOTNET}
if not AOwnedByIndy then begin
Result := TIdUTF7Encoding.Create;
Exit;
end;
{$ENDIF}
Result := IndyTextEncoding_UTF7;
end;
{$I IdDeprecatedImplBugOff.inc}
function IndyUTF8Encoding{$IFNDEF DOTNET}(const AOwnedByIndy: Boolean = True){$ENDIF}: IIdTextEncoding;
{$I IdDeprecatedImplBugOn.inc}
begin
{$IFNDEF DOTNET}
if not AOwnedByIndy then begin
Result := TIdUTF8Encoding.Create;
Exit;
end;
{$ENDIF}
Result := IndyTextEncoding_UTF8;
end;
{$IFDEF UNIX}
function HackLoadFileName(const ALibName, ALibVer : String) : string; {$IFDEF USE_INLINE} inline; {$ENDIF}
begin
{$IFDEF DARWIN}
Result := ALibName+ALibVer+LIBEXT;
{$ELSE}
{$IFDEF IOS}
Result := ALibName+ALibVer+LIBEXT;
{$ELSE}
Result := ALibName+LIBEXT+ALibVer;
{$ENDIF}
{$ENDIF}
end;
function HackLoad(const ALibName : String; const ALibVersions : array of String) : HMODULE;
var
i : Integer;
begin
Result := NilHandle;
for i := Low(ALibVersions) to High(ALibVersions) do
begin
{$IFDEF USE_SAFELOADLIBRARY}
Result := SafeLoadLibrary(HackLoadFileName(ALibName,ALibVersions[i]));
{$ELSE}
{$IFDEF KYLIXCOMPAT}
// Workaround that is required under Linux (changed RTLD_GLOBAL with RTLD_LAZY Note: also work with LoadLibrary())
Result := HMODULE(dlopen(PAnsiChar(HackLoadFileName(ALibName,ALibVersions[i])), RTLD_LAZY));
{$ELSE}
Result := LoadLibrary(HackLoadFileName(ALibName,ALibVersions[i]));
{$ENDIF}
{$ENDIF}
{$IFDEF USE_INVALIDATE_MOD_CACHE}
InvalidateModuleCache;
{$ENDIF}
if Result <> NilHandle then begin
break;
end;
end;
end;
{$ENDIF}
procedure IndyRaiseLastError;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
{$IFNDEF HAS_RaiseLastOSError}
RaiseLastWin32Error;
{$ELSE}
RaiseLastOSError;
{$ENDIF}
end;
{$IFDEF HAS_Exception_RaiseOuterException}
procedure IndyRaiseOuterException(AOuterException: Exception);
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Exception.RaiseOuterException(AOuterException);
end;
{$ELSE}
{$IFDEF DCC}
// RLebeau: There is no Exception.InnerException property to capture the inner
// exception into, but we can still raise the outer exception using Delphi's
// 'raise ... at [address]' syntax, at least. This way, the debugger (and
// exception loggers) can show the outer exception occuring in the caller
// rather than inside this function...
{$IFDEF HAS_System_ReturnAddress}
procedure IndyRaiseOuterException(AOuterException: Exception);
begin
raise AOuterException at ReturnAddress;
end;
{$ELSE}
// RLebeau: Delphi RTL functions like SysUtils.Abort(), Classes.TList.Error(),
// and Classes.TStrings.Error() raise their respective exceptions at the
// caller's return address using Delphi's 'raise ... at [address]' syntax,
// however they do so in different ways depending on Delphi version!
//
// ----------------
// SysUtils.Abort()
// ----------------
// Delphi 5-2007: Abort() calls an internal helper function that returns the
// caller's return address from the call stack - [EBP-4] in Delphi 5, [EBP+4]
// in Delphi 6+ - and then passes that value to 'raise'. Not sure why [EBP-4]
// was being used in Delphi 5. Maybe a typo?
//
// Delphi 2009-XE: Abort() JMP's into an internal helper procedure that takes
// a Pointer parameter as input (passed in EAX) and passes it to 'raise'.
// Delphi 2009-2010 POP's the caller's return address from the call stack
// into EAX. Delphi XE simply MOV's [ESP] into EAX instead.
// ----------------
// TList.Error()
// TStrings.Error()
// ----------------
// Delphi 5-2010: Error() calls an internal helper function that returns the
// caller's return address from the call stack - always [EBP+4] - and then passes
// that value to 'raise'.
//
// Delphi XE: no helper is used. Error() is wrapped with {$O-} to force a stack
// frame, and then reads the caller's return address directly from the call stack
// (using pointer math to find it) and passes it to 'raise'.
// ----------------
//
// To be safe, we will use the MOV [ESP] approach here, as it is the simplest.
// We only have to worry about this in Delphi's Windows 32bit compiler, as the
// 64bit and mobile compilers have System.ReturnAddress available...
// disable stack frames to reduce instructions
{$IFOPT W+} // detect stack frames
{$DEFINE _WPlusWasEnabled}
{$W-} // turn off stack frames
{$ENDIF}
procedure IndyRaiseOuterException(AOuterException: Exception);
procedure RaiseE(E: Exception; ReturnAddr: Pointer);
begin
raise E at ReturnAddr;
end;
asm
// AOuterException is already in EAX...
// MOV EAX, AOuterException
MOV EDX, [ESP]
JMP RaiseE
end;
{$IFDEF _WPlusWasEnabled}
{$UNDEF _WPlusWasEnabled}
{$W+}
{$ENDIF}
{$ENDIF}
{$ELSE}
// Not Delphi, so just raise the exception as-is until we know what else to do with it...
procedure IndyRaiseOuterException(AOuterException: Exception);
begin
raise AOuterException;
end;
{$ENDIF}
{$ENDIF}
{$IFNDEF DOTNET}
function InterlockedExchangeTHandle(var VTarget: THandle; const AValue: THandle): THandle;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
{$IFDEF HAS_TInterlocked}
{$IFDEF THANDLE_32}
Result := THandle(TInterlocked.Exchange(Integer(VTarget), Integer(AValue)));
{$ENDIF}
//Temporary workaround. TInterlocked for Emb really should accept 64 bit unsigned values as set of parameters
//for TInterlocked.Exchange since 64-bit wide integers are common on 64 bit platforms.
{$IFDEF THANDLE_64}
Result := THandle(TInterlocked.Exchange(Int64(VTarget), Int64(AValue)));
{$ENDIF}
{$ELSE}
{$IFDEF THANDLE_32}
Result := THandle(InterlockedExchange(Integer(VTarget), Integer(AValue)));
{$ENDIF}
{$IFDEF THANDLE_64}
Result := THandle(InterlockedExchange64(Int64(VTarget), Int64(AValue)));
{$ENDIF}
{$ENDIF}
end;
{$UNDEF DYNAMICLOAD_InterlockedCompareExchange}
{$IFNDEF HAS_TInterlocked}
{$IFNDEF FPC}
// RLebeau: InterlockedCompareExchange() is not available prior to Win2K,
// so need to fallback to some other logic on older systems. Not too many
// people still support those systems anymore, so we will make this optional.
//
// InterlockedCompareExchange64(), on the other hand, is not available until
// Windows Vista (and not defined in any version of Windows.pas up to Delphi
// XE), so always dynamically load it in order to support WinXP 64-bit...
{$IFDEF CPU64}
{$DEFINE DYNAMICLOAD_InterlockedCompareExchange}
{$ELSE}
{.$DEFINE STATICLOAD_InterlockedCompareExchange}
{$ENDIF}
{$ENDIF}
{$ENDIF}
{$IFDEF DYNAMICLOAD_InterlockedCompareExchange}
// See http://code.google.com/p/delphi-toolbox/source/browse/trunk/RTLEx/RTLEx.BasicOp.Atomic.pas
// for how to perform interlocked operations in assembler...
type
TInterlockedCompareExchangeFunc = function(var Destination: PtrInt; Exchange, Comparand: PtrInt): PtrInt; stdcall;
var
InterlockedCompareExchange: TInterlockedCompareExchangeFunc = nil;
function Impl_InterlockedCompareExchange(var Destination: PtrInt; Exchange, Comparand: PtrInt): PtrInt; stdcall;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
{$IFDEF CPU64}
// TODO: use LOCK CMPXCHG8B directly so this is more atomic...
{$ELSE}
// TODO: use LOCK CMPXCHG directly so this is more atomic...
{$ENDIF}
Result := Destination;
if Destination = Comparand then begin
Destination := Exchange;
end;
end;
function Stub_InterlockedCompareExchange(var Destination: PtrInt; Exchange, Comparand: PtrInt): PtrInt; stdcall;
function GetImpl: Pointer;
const
cKernel32 = 'KERNEL32'; {do not localize}
// TODO: what is Embarcadero's 64-bit define going to be?
cInterlockedCompareExchange = {$IFDEF CPU64}'InterlockedCompareExchange64'{$ELSE}'InterlockedCompareExchange'{$ENDIF}; {do not localize}
begin
Result := GetProcAddress(GetModuleHandle(cKernel32), cInterlockedCompareExchange);
if Result = nil then begin
Result := @Impl_InterlockedCompareExchange;
end;
end;
begin
@InterlockedCompareExchange := GetImpl();
Result := InterlockedCompareExchange(Destination, Exchange, Comparand);
end;
{$ENDIF}
function InterlockedCompareExchangePtr(var VTarget: Pointer; const AValue, Compare: Pointer): Pointer;
{$IFNDEF DYNAMICLOAD_InterlockedCompareExchange}
{$IFDEF USE_INLINE}inline;{$ENDIF}
{$ENDIF}
begin
{$IFDEF DYNAMICLOAD_InterlockedCompareExchange}
Result := Pointer(IdGlobal.InterlockedCompareExchange(PtrInt(VTarget), PtrInt(AValue), PtrInt(Compare)));
{$ELSE}
{$IFDEF HAS_TInterlocked}
Result := TInterlocked.CompareExchange(VTarget, AValue, Compare);
{$ELSE}
{$IFDEF HAS_InterlockedCompareExchangePointer}
Result := InterlockedCompareExchangePointer(VTarget, AValue, Compare);
{$ELSE}
{$IFDEF HAS_InterlockedCompareExchange_Pointers}
//work around a conflicting definition for InterlockedCompareExchange
Result := {$IFDEF FPC}system.{$ENDIF}InterlockedCompareExchange(VTarget, AValue, Compare);
{$ELSE}
{$IFDEF FPC}
Result := Pointer(
{$IFDEF CPU64}InterlockedCompareExchange64{$ELSE}InterlockedCompareExchange{$ENDIF}
(PtrInt(VTarget), PtrInt(AValue), PtrInt(Compare))
);
{$ELSE}
// Delphi 64-bit is handled by HAS_InterlockedCompareExchangePointer
Result := Pointer(InterlockedCompareExchange(Integer(VTarget), Integer(AValue), Integer(Compare)));
{$ENDIF}
{$ENDIF}
{$ENDIF}
{$ENDIF}
{$ENDIF}
end;
function InterlockedCompareExchangeObj(var VTarget: TObject; const AValue, Compare: TObject): TObject;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
{$IFDEF USE_OBJECT_ARC}
// for ARC, we have to use the TObject overload of TInterlocked to ensure
// that the reference counts of the objects are managed correctly...
Result := TInterlocked.CompareExchange(VTarget, AValue, Compare);
{$ELSE}
Result := TObject(InterlockedCompareExchangePtr(Pointer(VTarget), Pointer(AValue), Pointer(Compare)));
{$ENDIF}
end;
function InterlockedCompareExchangeIntf(var VTarget: IInterface; const AValue, Compare: IInterface): IInterface;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
// we have to ensure that the reference counts of the interfaces are managed correctly...
if AValue <> nil then begin
AValue._AddRef;
end;
Result := IInterface(InterlockedCompareExchangePtr(Pointer(VTarget), Pointer(AValue), Pointer(Compare)));
if (AValue <> nil) and (Pointer(Result) <> Pointer(Compare)) then begin
AValue._Release;
end;
end;
{$ENDIF}
{Little Endian Byte order functions from:
From: http://community.borland.com/article/0,1410,16854,00.html
Big-endian and little-endian formated integers - by Borland Developer Support Staff
Note that I will NOT do big Endian functions because the stacks can handle that
with HostToNetwork and NetworkToHost functions.
You should use these functions for writing data that sent and received in Little
Endian Form. Do NOT assume endianness of what's written. It can work in unpredictable
ways on other architectures.
}
function HostToLittleEndian(const AValue : UInt16) : UInt16;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
{$IFDEF DOTNET}
//I think that is Little Endian but I'm not completely sure
Result := AValue;
{$ELSE}
{$IFDEF ENDIAN_LITTLE}
Result := AValue;
{$ENDIF}
{$IFDEF ENDIAN_BIG}
Result := swap(AValue);
{$ENDIF}
{$ENDIF}
end;
function HostToLittleEndian(const AValue : UInt32) : UInt32;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
{$IFDEF DOTNET}
//I think that is Little Endian but I'm not completely sure
Result := AValue;
{$ELSE}
{$IFDEF ENDIAN_LITTLE}
Result := AValue;
{$ENDIF}
{$IFDEF ENDIAN_BIG}
Result := swap(AValue shr 16) or (UInt32(swap(AValue and $FFFF)) shl 16);
{$ENDIF}
{$ENDIF}
end;
function HostToLittleEndian(const AValue : Integer) : Integer;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
{$IFDEF DOTNET}
//I think that is Little Endian but I'm not completely sure
Result := AValue;
{$ELSE}
{$IFDEF ENDIAN_LITTLE}
Result := AValue;
{$ENDIF}
{$IFDEF ENDIAN_BIG}
Result := swap(AValue);
{$ENDIF}
{$ENDIF}
end;
function LittleEndianToHost(const AValue : UInt16) : UInt16;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
{$IFDEF DOTNET}
//I think that is Little Endian but I'm not completely sure
Result := AValue;
{$ELSE}
{$IFDEF ENDIAN_LITTLE}
Result := AValue;
{$ENDIF}
{$IFDEF ENDIAN_BIG}
Result := swap(AValue);
{$ENDIF}
{$ENDIF}
end;
function LittleEndianToHost(const AValue : UInt32): UInt32;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
{$IFDEF DOTNET}
//I think that is Little Endian but I'm not completely sure
Result := AValue;
{$ELSE}
{$IFDEF ENDIAN_LITTLE}
Result := AValue;
{$ENDIF}
{$IFDEF ENDIAN_BIG}
Result := swap(AValue shr 16) or (UInt32(swap(AValue and $FFFF)) shl 16);
{$ENDIF}
{$ENDIF}
end;
function LittleEndianToHost(const AValue : Integer): Integer;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
{$IFDEF DOTNET}
//I think that is Little Endian but I'm not completely sure
Result := AValue;
{$ELSE}
{$IFDEF ENDIAN_LITTLE}
Result := AValue;
{$ENDIF}
{$IFDEF ENDIAN_BIG}
Result := Swap(AValue);
{$ENDIF}
{$ENDIF}
end;
// TODO: add an AIndex parameter
procedure FillBytes(var VBytes : TIdBytes; const ACount : Integer; const AValue : Byte);
{$IFDEF STRING_IS_ANSI}
{$IFDEF USE_INLINE}inline;{$ENDIF}
{$ELSE}
var
I: Integer;
{$ENDIF}
begin
// RLebeau: FillChar() is bad to use on Delphi/C++Builder 2009+ for filling
// byte buffers as it is actually designed for filling character buffers
// instead. Now that Char maps to WideChar, this causes problems for FillChar().
{$IFDEF STRING_IS_UNICODE}
//System.&Array.Clear(VBytes, 0, ACount);
// TODO: optimize this
for I := 0 to ACount-1 do begin
VBytes[I] := AValue;
end;
{$ELSE}
FillChar(VBytes[0], ACount, AValue);
{$ENDIF}
end;
// RLebeau 10/22/2013: prior to Delphi 2010, fmCreate was an all-encompassing
// bitmask, no other flags could be combined with it. The RTL was updated in
// Delphi 2010 to allow other flags to be specified along with fmCreate. So
// at best, we will now be able to allow read-only access to other processes
// in Delphi 2010 and later, and at worst we will continue having exclusive
// right to the file in Delphi 2009 and earlier, just like we always did...
constructor TIdFileCreateStream.Create(const AFile : String);
begin
inherited Create(AFile, fmCreate or fmOpenReadWrite or fmShareDenyWrite);
end;
constructor TIdAppendFileStream.Create(const AFile : String);
var
LFlags: Word;
begin
LFlags := fmOpenReadWrite or fmShareDenyWrite;
if not FileExists(AFile) then begin
LFlags := LFLags or fmCreate;
end;
inherited Create(AFile, LFlags);
if (LFlags and fmCreate) = 0 then begin
TIdStreamHelper.Seek(Self, 0, soEnd);
end;
end;
constructor TIdReadFileNonExclusiveStream.Create(const AFile : String);
begin
inherited Create(AFile, fmOpenRead or fmShareDenyNone);
end;
constructor TIdReadFileExclusiveStream.Create(const AFile : String);
begin
inherited Create(AFile, fmOpenRead or fmShareDenyWrite);
end;
function IsASCIILDH(const AByte: Byte): Boolean;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Result := True;
//Verify the absence of non-LDH ASCII code points; that is, the
//absence of 0..2C, 2E..2F, 3A..40, 5B..60, and 7B..7F.
//Permissable chars are in this set
//['-','0'..'9','A'..'Z','a'..'z']
if AByte <= $2C then begin
Result := False;
end
else if (AByte >= $2E) and (AByte <= $2F) then begin
Result := False;
end
else if (AByte >= $3A) and (AByte <= $40) then begin
Result := False;
end
else if (AByte >= $5B) and (AByte <= $60) then begin
Result := False;
end
else if (AByte >= $7B) and (AByte <= $7F) then begin
Result := False;
end;
end;
function IsASCIILDH(const ABytes: TIdBytes): Boolean;
var
i: Integer;
begin
for i := 0 to Length(ABytes)-1 do begin
if not IsASCIILDH(ABytes[i]) then
begin
Result := False;
Exit;
end;
end;
Result := True;
end;
function IsASCII(const AByte: Byte): Boolean;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Result := AByte <= $7F;
end;
function IsASCII(const ABytes: TIdBytes): Boolean;
var
i: Integer;
begin
for i := 0 to Length(ABytes) -1 do begin
if not IsASCII(ABytes[i]) then begin
Result := False;
Exit;
end;
end;
Result := True;
end;
function StartsWithACE(const ABytes: TIdBytes): Boolean;
const
cDash = Ord('-');
var
LS: {$IFDEF STRING_IS_IMMUTABLE}TIdStringBuilder{$ELSE}string{$ENDIF};
begin
Result := False;
if Length(ABytes) >= 4 then
begin
if (ABytes[2] = cDash) and (ABytes[3] = cDash) then
begin
// TODO: just do byte comparisons so String conversions are not needed...
{$IFDEF STRING_IS_IMMUTABLE}
LS := TIdStringBuilder.Create(2);
LS.Append(Char(ABytes[0]));
LS.Append(Char(ABytes[1]));
{$ELSE}
SetLength(LS, 2);
LS[1] := Char(ABytes[0]);
LS[2] := Char(ABytes[1]);
{$ENDIF}
Result := PosInStrArray(LS{$IFDEF STRING_IS_IMMUTABLE}.ToString{$ENDIF},
['bl','bq','dq','lq','mq','ra','wq','zq'], False) > -1;{do not localize}
end;
end;
end;
function PosInSmallIntArray(const ASearchInt: Int16; const AArray: array of Int16): Integer;
begin
for Result := Low(AArray) to High(AArray) do begin
if ASearchInt = AArray[Result] then begin
Exit;
end;
end;
Result := -1;
end;
{This searches an array of string for an occurance of SearchStr}
function PosInStrArray(const SearchStr: string; const Contents: array of string; const CaseSensitive: Boolean = True): Integer;
begin
for Result := Low(Contents) to High(Contents) do begin
if CaseSensitive then begin
if SearchStr = Contents[Result] then begin
Exit;
end;
end else begin
if TextIsSame(SearchStr, Contents[Result]) then begin
Exit;
end;
end;
end;
Result := -1;
end;
//IPv4 address conversion
function ByteToHex(const AByte: Byte): string;
{$IFDEF USE_INLINE}inline;{$ENDIF}
{$IFDEF STRING_IS_IMMUTABLE}
var
LSB: TIdStringBuilder;
{$ENDIF}
begin
{$IFDEF STRING_IS_IMMUTABLE}
LSB := TIdStringBuilder.Create(2);
LSB.Append(IdHexDigits[(AByte and $F0) shr 4]);
LSB.Append(IdHexDigits[AByte and $F]);
Result := LSB.ToString;
{$ELSE}
SetLength(Result, 2);
Result[1] := IdHexDigits[(AByte and $F0) shr 4];
Result[2] := IdHexDigits[AByte and $F];
{$ENDIF}
end;
function UInt32ToHex(const ALongWord : UInt32) : String;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Result := ByteToHex((ALongWord and $FF000000) shr 24)
+ ByteToHex((ALongWord and $00FF0000) shr 16)
+ ByteToHex((ALongWord and $0000FF00) shr 8)
+ ByteToHex(ALongWord and $000000FF);
end;
{$I IdDeprecatedImplBugOff.inc}
function LongWordToHex(const ALongWord : UInt32) : String;
{$I IdDeprecatedImplBugOn.inc}
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Result := UInt32ToHex(ALongWord);
end;
function ToHex(const AValue: TIdBytes; const ACount: Integer = -1;
const AIndex: Integer = 0): string;
{$IFDEF USE_INLINE}inline;{$ENDIF}
var
I, LCount: Integer;
{$IFDEF STRING_IS_IMMUTABLE}
LSB: TIdStringBuilder;
{$ENDIF}
begin
LCount := IndyLength(AValue, ACount, AIndex);
if LCount > 0 then begin
{$IFDEF STRING_IS_IMMUTABLE}
LSB := TIdStringBuilder.Create(LCount*2);
{$ELSE}
SetLength(Result, LCount*2);
{$ENDIF}
for I := 0 to LCount-1 do begin
{$IFDEF STRING_IS_IMMUTABLE}
LSB.Append(IdHexDigits[(AValue[AIndex+I] and $F0) shr 4]);
LSB.Append(IdHexDigits[AValue[AIndex+I] and $F]);
{$ELSE}
Result[I*2+1] := IdHexDigits[(AValue[AIndex+I] and $F0) shr 4];
Result[I*2+2] := IdHexDigits[AValue[AIndex+I] and $F];
{$ENDIF}
end;
{$IFDEF STRING_IS_IMMUTABLE}
Result := LSB.ToString;
{$ENDIF}
end else begin
Result := '';
end;
end;
function ToHex(const AValue: array of UInt32): string;
var
{$IFDEF STRING_IS_IMMUTABLE}
LSB: TIdStringBuilder;
{$ENDIF}
P: {$IFDEF DOTNET}TIdBytes{$ELSE}PByteArray{$ENDIF};
i, j: Integer;
begin
Result := '';
if Length(AValue) > 0 then
begin
{$IFDEF STRING_IS_IMMUTABLE}
LSB := TIdStringBuilder.Create(Length(AValue)*SizeOf(UInt32)*2);
{$ELSE}
SetLength(Result, Length(AValue)*SizeOf(UInt32)*2);
{$ENDIF}
for i := 0 to High(AValue) do begin
{$IFDEF DOTNET}
P := ToBytes(AValue[i]);
{$ELSE}
P := PByteArray(@AValue[i]);
{$ENDIF}
for j := 0 to SizeOf(UInt32)-1 do begin
{$IFDEF STRING_IS_IMMUTABLE}
LSB.Append(IdHexDigits[(P[j] and $F0) shr 4]);
LSB.Append(IdHexDigits[P[j] and $F]);
{$ELSE}
Result[(i*SizeOf(UInt32))+(j*2)+1] := IdHexDigits[(P^[j] and $F0) shr 4];
Result[(i*SizeOf(UInt32))+(j*2)+2] := IdHexDigits[P^[j] and $F];
{$ENDIF}
end;
end;//for
{$IFDEF STRING_IS_IMMUTABLE}
Result := LSB.ToString;
{$ENDIF}
end;
end;
function IPv4ToHex(const AIPAddress: string; const ADotted: Boolean): string;
var
i: Integer;
LBuf, LTmp: string;
begin
LBuf := Trim(AIPAddress);
Result := IdHexPrefix;
for i := 0 to 3 do begin
LTmp := ByteToHex(IndyStrToInt(Fetch(LBuf, '.', True)));
if ADotted then begin
Result := Result + '.' + IdHexPrefix + LTmp;
end else begin
Result := Result + LTmp;
end;
end;
end;
{$IFNDEF DOTNET}
function OctalToInt64(const AValue: string): Int64;
var
i: Integer;
begin
Result := 0;
for i := 1 to Length(AValue) do begin
Result := (Result shl 3) + IndyStrToInt(AValue[i], 0);
end;
end;
{$ENDIF}
function ByteToOctal(const AByte: Byte): string;
{$IFDEF USE_INLINE}inline;{$ENDIF}
{$IFDEF STRING_IS_IMMUTABLE}
var
LSB: TIdStringBuilder;
C: Char;
{$ENDIF}
begin
{$IFDEF STRING_IS_IMMUTABLE}
C := IdOctalDigits[(AByte shr 6) and $7];
if C <> '0' then begin
LSB := TIdStringBuilder.Create(4);
LSB.Append(Char('0')); {do not localize}
end else begin
LSB := TIdStringBuilder.Create(3);
end;
LSB.Append(C);
LSB.Append(IdOctalDigits[(AByte shr 3) and $7]);
LSB.Append(IdOctalDigits[AByte and $7]);
Result := LSB.ToString;
{$ELSE}
SetLength(Result, 3);
Result[1] := IdOctalDigits[(AByte shr 6) and $7];
Result[2] := IdOctalDigits[(AByte shr 3) and $7];
Result[3] := IdOctalDigits[AByte and $7];
if Result[1] <> '0' then begin {do not localize}
Result := '0' + Result; {do not localize}
end;
{$ENDIF}
end;
function IPv4ToOctal(const AIPAddress: string): string;
var
i: Integer;
LBuf: string;
begin
LBuf := Trim(AIPAddress);
Result := ByteToOctal(IndyStrToInt(Fetch(LBuf, '.', True), 0));
for i := 0 to 2 do begin
Result := Result + '.' + ByteToOctal(IndyStrToInt(Fetch(LBuf, '.', True), 0));
end;
end;
procedure CopyTIdBytes(const ASource: TIdBytes; const ASourceIndex: Integer;
var VDest: TIdBytes; const ADestIndex: Integer; const ALength: Integer);
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
{$IFDEF DOTNET}
System.array.Copy(ASource, ASourceIndex, VDest, ADestIndex, ALength);
{$ELSE}
//if these asserts fail, then it indicates an attempted buffer overrun.
Assert(ASourceIndex >= 0);
Assert((ASourceIndex+ALength) <= Length(ASource));
Move(ASource[ASourceIndex], VDest[ADestIndex], ALength);
{$ENDIF}
end;
procedure CopyTIdChar(const ASource: Char; var VDest: TIdBytes; const ADestIndex: Integer;
ADestEncoding: IIdTextEncoding = nil
{$IFDEF STRING_IS_ANSI}; ASrcEncoding: IIdTextEncoding = nil{$ENDIF}
);
var
LChars: {$IFDEF DOTNET}array[0..0] of Char{$ELSE}TIdWideChars{$ENDIF};
begin
EnsureEncoding(ADestEncoding);
{$IFDEF STRING_IS_UNICODE}
{$IFNDEF DOTNET}
SetLength(LChars, 1);
{$ENDIF}
LChars[0] := ASource;
ADestEncoding.GetBytes(LChars, 0, 1, VDest, ADestIndex);
{$ELSE}
EnsureEncoding(ASrcEncoding, encOSDefault);
LChars := ASrcEncoding.GetChars(RawToBytes(ASource, 1));
ADestEncoding.GetBytes(LChars, 0, Length(LChars), VDest, ADestIndex);
{$ENDIF}
end;
procedure CopyTIdInt16(const ASource: Int16; var VDest: TIdBytes; const ADestIndex: Integer);
{$IFDEF DOTNET}
var
LShort : TIdBytes;
{$ELSE}
{$IFDEF USE_INLINE}inline;{$ENDIF}
{$ENDIF}
begin
{$IFDEF DOTNET}
LShort := System.BitConverter.GetBytes(ASource);
System.array.Copy(LShort, 0, VDest, ADestIndex, SizeOf(Int16));
{$ELSE}
PInt16(@VDest[ADestIndex])^ := ASource;
{$ENDIF}
end;
{$I IdDeprecatedImplBugOff.inc}
procedure CopyTIdShort(const ASource: Int16; var VDest: TIdBytes; const ADestIndex: Integer);
{$I IdDeprecatedImplBugOn.inc}
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
CopyTIdInt16(ASource, VDest, ADestIndex);
end;
procedure CopyTIdUInt16(const ASource: UInt16; var VDest: TIdBytes; const ADestIndex: Integer);
{$IFDEF DOTNET}
var
LWord : TIdBytes;
{$ELSE}
{$IFDEF USE_INLINE}inline;{$ENDIF}
{$ENDIF}
begin
{$IFDEF DOTNET}
LWord := System.BitConverter.GetBytes(ASource);
System.array.Copy(LWord, 0, VDest, ADestIndex, SizeOf(UInt16));
{$ELSE}
PUInt16(@VDest[ADestIndex])^ := ASource;
{$ENDIF}
end;
{$I IdDeprecatedImplBugOff.inc}
procedure CopyTIdWord(const ASource: UInt16; var VDest: TIdBytes; const ADestIndex: Integer);
{$I IdDeprecatedImplBugOn.inc}
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
CopyTIdUInt16(ASource, VDest, ADestIndex);
end;
procedure CopyTIdUInt32(const ASource: UInt32; var VDest: TIdBytes; const ADestIndex: Integer);
{$IFDEF DOTNET}
var
LWord : TIdBytes;
{$ELSE}
{$IFDEF USE_INLINE}inline;{$ENDIF}
{$ENDIF}
begin
{$IFDEF DOTNET}
LWord := System.BitConverter.GetBytes(ASource);
System.array.Copy(LWord, 0, VDest, ADestIndex, SizeOf(UInt32));
{$ELSE}
PUInt32(@VDest[ADestIndex])^ := ASource;
{$ENDIF}
end;
{$I IdDeprecatedImplBugOff.inc}
procedure CopyTIdLongWord(const ASource: UInt32; var VDest: TIdBytes; const ADestIndex: Integer);
{$I IdDeprecatedImplBugOn.inc}
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
CopyTIdUInt32(ASource, VDest, ADestIndex);
end;
procedure CopyTIdInt32(const ASource: Int32; var VDest: TIdBytes; const ADestIndex: Integer);
{$IFDEF DOTNET}
var
LInt : TIdBytes;
{$ELSE}
{$IFDEF USE_INLINE}inline;{$ENDIF}
{$ENDIF}
begin
{$IFDEF DOTNET}
LInt := System.BitConverter.GetBytes(ASource);
System.array.Copy(LInt, 0, VDest, ADestIndex, SizeOf(Int32));
{$ELSE}
PInt32(@VDest[ADestIndex])^ := ASource;
{$ENDIF}
end;
{$I IdDeprecatedImplBugOff.inc}
procedure CopyTIdLongInt(const ASource: Int32; var VDest: TIdBytes; const ADestIndex: Integer);
{$I IdDeprecatedImplBugOn.inc}
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
CopyTIdInt32(ASource, VDest, ADestIndex);
end;
procedure CopyTIdInt64(const ASource: Int64; var VDest: TIdBytes; const ADestIndex: Integer);
{$IFDEF DOTNET}
var
LWord : TIdBytes;
{$ELSE}
{$IFDEF USE_INLINE}inline;{$ENDIF}
{$ENDIF}
begin
{$IFDEF DOTNET}
LWord := System.BitConverter.GetBytes(ASource);
System.array.Copy(LWord, 0, VDest, ADestIndex, SizeOf(Int64));
{$ELSE}
PInt64(@VDest[ADestIndex])^ := ASource;
{$ENDIF}
end;
procedure CopyTIdUInt64(const ASource: TIdUInt64;
var VDest: TIdBytes; const ADestIndex: Integer);
{$IFDEF DOTNET}
var
LWord : TIdBytes;
{$ELSE}
{$IFDEF USE_INLINE}inline;{$ENDIF}
{$ENDIF}
begin
{$IFDEF DOTNET}
LWord := System.BitConverter.GetBytes(ASource);
System.array.Copy(LWord, 0, VDest, ADestIndex, SizeOf(UInt64));
{$ELSE}
PUInt64(@VDest[ADestIndex])^ := ASource{$IFDEF TIdUInt64_IS_NOT_NATIVE}.QuadPart{$ENDIF};
{$ENDIF}
end;
procedure CopyTIdTicks(const ASource: TIdTicks; var VDest: TIdBytes; const ADestIndex: Integer);
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
{$IFDEF UInt64_IS_NATIVE}
CopyTIdUInt64(ASource, VDest, ADestIndex);
{$ELSE}
CopyTIdInt64(ASource, VDest, ADestIndex);
{$ENDIF}
end;
procedure CopyTIdIPV6Address(const ASource: TIdIPv6Address; var VDest: TIdBytes; const ADestIndex: Integer);
{$IFDEF DOTNET}
var
i : Integer;
{$ELSE}
{$IFDEF USE_INLINE}inline;{$ENDIF}
{$ENDIF}
begin
{$IFDEF DOTNET}
for i := 0 to 7 do begin
CopyTIdUInt16(ASource[i], VDest, ADestIndex + (i * 2));
end;
{$ELSE}
Move(ASource, VDest[ADestIndex], 16);
{$ENDIF}
end;
procedure CopyTIdByteArray(const ASource: array of Byte; const ASourceIndex: Integer;
var VDest: TIdBytes; const ADestIndex: Integer; const ALength: Integer);
begin
{$IFDEF DOTNET}
System.array.Copy(ASource, ASourceIndex, VDest, ADestIndex, ALength);
{$ELSE}
Move(ASource[ASourceIndex], VDest[ADestIndex], ALength);
{$ENDIF}
end;
procedure CopyTIdString(const ASource: String; var VDest: TIdBytes;
const ADestIndex: Integer; const ALength: Integer = -1;
ADestEncoding: IIdTextEncoding = nil
{$IFDEF STRING_IS_ANSI}; ASrcEncoding: IIdTextEncoding = nil{$ENDIF}
); overload;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
CopyTIdString(ASource, 1, VDest, ADestIndex, ALength, ADestEncoding
{$IFDEF STRING_IS_ANSI}, ASrcEncoding{$ENDIF}
);
end;
procedure CopyTIdString(const ASource: String; const ASourceIndex: Integer;
var VDest: TIdBytes; const ADestIndex: Integer; const ALength: Integer = -1;
ADestEncoding: IIdTextEncoding = nil
{$IFDEF STRING_IS_ANSI}; ASrcEncoding: IIdTextEncoding = nil{$ENDIF}
); overload;
{$IFDEF USE_INLINE}inline;{$ENDIF}
var
LLength: Integer;
{$IFDEF STRING_IS_ANSI}
LTmp: TIdWideChars;
{$ENDIF}
begin
{$IFDEF STRING_IS_ANSI}
LTmp := nil; // keep the compiler happy
{$ENDIF}
LLength := IndyLength(ASource, ALength, ASourceIndex);
if LLength > 0 then begin
EnsureEncoding(ADestEncoding);
{$IFDEF STRING_IS_UNICODE}
ADestEncoding.GetBytes(ASource, ASourceIndex, LLength, VDest, ADestIndex);
{$ELSE}
EnsureEncoding(ASrcEncoding, encOSDefault);
LTmp := ASrcEncoding.GetChars(RawToBytes(ASource[ASourceIndex], LLength)); // convert to Unicode
ADestEncoding.GetBytes(LTmp, 0, Length(LTmp), VDest, ADestIndex);
{$ENDIF}
end;
end;
procedure DebugOutput(const AText: string);
{$IFDEF WINDOWS}
{$IFDEF STRING_UNICODE_MISMATCH}
var
LTemp: TIdPlatformString;
{$ELSE}
{$IFDEF USE_INLINE}inline;{$ENDIF}
{$ENDIF}
{$ELSE}
{$IFDEF USE_INLINE}inline;{$ENDIF}
{$ENDIF}
begin
{$IFDEF KYLIX}
__write(stderr, AText, Length(AText));
__write(stderr, EOL, Length(EOL));
{$ENDIF}
{$IFDEF WINDOWS}
{$IFDEF STRING_UNICODE_MISMATCH}
LTemp := TIdPlatformString(AText); // explicit convert to Ansi/Unicode
OutputDebugString(PIdPlatformChar(LTemp));
{$ELSE}
OutputDebugString(PChar(AText));
{$ENDIF}
{$ENDIF}
{$IFDEF DOTNET}
System.Diagnostics.Debug.WriteLine(AText);
{$ENDIF}
end;
function CurrentThreadId: TIdThreadID;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
{$IFDEF DOTNET}
{$IFDEF DOTNET_2_OR_ABOVE}
{
[Warning] IdGlobal.pas(1416): W1000 Symbol 'GetCurrentThreadId'
is deprecated: 'AppDomain.GetCurrentThreadId has been deprecated because
it does not provide a stable Id when managed threads are running on fibers
(aka lightweight threads). To get a stable identifier for a managed thread,
use the ManagedThreadId property on Thread.
http://go.microsoft.com/fwlink/?linkid=14202'
}
Result := System.Threading.Thread.CurrentThread.ManagedThreadId;
// Thread.ManagedThreadId;
{$ENDIF}
{$IFDEF DOTNET_1_1}
// SG: I'm not sure if this return the handle of the dotnet thread or the handle of the application domain itself (or even if there is a difference)
Result := AppDomain.GetCurrentThreadId;
// RLebeau
// TODO: find if there is something like the following instead:
// System.Diagnostics.Thread.GetCurrentThread.ID
// System.Threading.Thread.CurrentThread.ID
{$ENDIF}
{$ELSE}
// TODO: is GetCurrentThreadId() available on Linux?
Result := GetCurrentThreadID;
{$ENDIF}
end;
function CurrentProcessId: TIdPID;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
{$IFDEF KYLIXCOMPAT}
Result := getpid;
{$ENDIF}
{$IFDEF USE_VCL_POSIX}
Result := getpid;
{$ENDIF}
{$IFDEF USE_BASEUNIX}
Result := fpgetpid;
{$ENDIF}
{$IFDEF WINDOWS}
Result := GetCurrentProcessID;
{$ENDIF}
{$IFDEF DOTNET}
Result := System.Diagnostics.Process.GetCurrentProcess.ID;
{$ENDIF}
end;
function Fetch(var AInput: string; const ADelim: string = IdFetchDelimDefault;
const ADelete: Boolean = IdFetchDeleteDefault;
const ACaseSensitive: Boolean = IdFetchCaseSensitiveDefault): string;
{$IFDEF USE_INLINE}inline;{$ENDIF}
var
LPos: Integer;
begin
if ACaseSensitive then begin
if ADelim = #0 then begin
// AnsiPos does not work with #0
LPos := Pos(ADelim, AInput);
end else begin
LPos := IndyPos(ADelim, AInput);
end;
if LPos = 0 then begin
Result := AInput;
if ADelete then begin
AInput := ''; {Do not Localize}
end;
end
else begin
Result := Copy(AInput, 1, LPos - 1);
if ADelete then begin
//slower Delete(AInput, 1, LPos + Length(ADelim) - 1); because the
//remaining part is larger than the deleted
AInput := Copy(AInput, LPos + Length(ADelim), MaxInt);
end;
end;
end else begin
Result := FetchCaseInsensitive(AInput, ADelim, ADelete);
end;
end;
function FetchCaseInsensitive(var AInput: string; const ADelim: string;
const ADelete: Boolean): string;
{$IFDEF USE_INLINE}inline;{$ENDIF}
var
LPos: Integer;
begin
if ADelim = #0 then begin
// AnsiPos does not work with #0
LPos := Pos(ADelim, AInput);
end else begin
//? may be AnsiUpperCase?
LPos := IndyPos(UpperCase(ADelim), UpperCase(AInput));
end;
if LPos = 0 then begin
Result := AInput;
if ADelete then begin
AInput := ''; {Do not Localize}
end;
end else begin
Result := Copy(AInput, 1, LPos - 1);
if ADelete then begin
//faster than Delete(AInput, 1, LPos + Length(ADelim) - 1); because the
//remaining part is larger than the deleted
AInput := Copy(AInput, LPos + Length(ADelim), MaxInt);
end;
end;
end;
function GetThreadHandle(AThread: TThread): TIdThreadHandle;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
{$IFDEF UNIX}
Result := AThread.ThreadID; // RLebeau: is it right to return an ID where a thread object handle is expected instead?
{$ENDIF}
{$IFDEF WINDOWS}
Result := AThread.Handle;
{$ENDIF}
{$IFDEF DOTNET}
Result := AThread.Handle;
{$ENDIF}
end;
{$IFDEF WINDOWS}
type
TGetTickCount64Func = function: UInt64; stdcall;
var
GetTickCount64: TGetTickCount64Func = nil;
function Impl_GetTickCount64: UInt64; stdcall;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
// TODO: implement some kind of accumulator so the Result
// keeps growing even when GetTickCount() wraps back to 0
Result := UInt64(Windows.GetTickCount);
end;
function Stub_GetTickCount64: UInt64; stdcall;
function GetImpl: Pointer;
begin
Result := GetProcAddress(GetModuleHandle('KERNEL32'), 'GetTickCount64'); {do not localize}
if Result = nil then begin
Result := @Impl_GetTickCount64;
end;
end;
begin
@GetTickCount64 := GetImpl();
Result := GetTickCount64();
end;
{$ENDIF}
{$I IdDeprecatedImplBugOff.inc}
function Ticks: UInt32;
{$I IdDeprecatedImplBugOn.inc}
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
// TODO: maybe throw an exception if Ticks64() exceeds the 49.7 day limit of UInt32?
Result := UInt32(Ticks64() mod High(UInt32));
end;
//RLebeau: FPC does not provide mach_timebase_info() and mach_absolute_time() yet...
{$IFDEF UNIX}
{$IFDEF DARWIN}
{$IFDEF FPC}
function mach_timebase_info(var TimebaseInfoData: TTimebaseInfoData): Integer; cdecl; external 'libc';
function mach_absolute_time: QWORD; cdecl; external 'libc';
{$ENDIF}
{$ELSE}
{$IFDEF USE_clock_gettime}
{$IFDEF LINUX}
// accordingly Linux's /usr/include/linux/time.h
const
CLOCK_MONOTONIC = 1;
{$ENDIF}
{$IFDEF FREEBSD}
// accordingly FreeBSD's /usr/include/time.h
const
CLOCK_MONOTONIC = 4;
{$ENDIF}
function clock_gettime(clockid: Integer; var pts: timespec): Integer; cdecl; external 'libc';
{$ENDIF}
{$ENDIF}
{$ENDIF}
function Ticks64: TIdTicks;
{$IFDEF DOTNET}
{$IFDEF USE_INLINE}inline;{$ENDIF}
{$ENDIF}
{$IFDEF UNIX}
{$IFDEF DARWIN}
{$IFDEF USE_INLINE} inline;{$ENDIF}
{$ELSE}
var
{$IFDEF USE_clock_gettime}
ts: timespec;
{$ELSE}
tv: timeval;
{$ENDIF}
{$ENDIF}
{$ENDIF}
{$IFDEF WINDOWS}
{$IFDEF USE_HI_PERF_COUNTER_FOR_TICKS}
var
nTime, freq: {$IFDEF WINCE}LARGE_INTEGER{$ELSE}Int64{$ENDIF};
{$ENDIF}
{$ENDIF}
begin
{$IFDEF UNIX}
{$IFDEF DARWIN}
// TODO: mach_absolute_time() does NOT count ticks while the system is
// sleeping! We can use time() to account for that:
//
// "time() carries on incrementing while the device is asleep, but of
// course can be manipulated by the operating system or user. However,
// the Kernel boottime (a timestamp of when the system last booted)
// also changes when the system clock is changed, therefore even though
// both these values are not fixed, the offset between them is."
//
// time_t uptime()
// {
// struct timeval boottime;
// int mib[2] = {CTL_KERN, KERN_BOOTTIME};
// size_t size = sizeof(boottime);
// time_t now;
// time_t uptime = -1;
// time(&now);
// if ((sysctl(mib, 2, &boottime, &size, NULL, 0) != -1) && (boottime.tv_sec != 0))
// {
// uptime = now - boottime.tv_sec;
// }
// return uptime;
// }
//
// However, KERN_BOOTTIME only has *seconds* precision (timeval.tv_usecs is always 0).
// mach_absolute_time() returns billionth of seconds, so divide by one million to get milliseconds
Result := (mach_absolute_time() * GMachTimeBaseInfo.numer) div (1000000 * GMachTimeBaseInfo.denom);
{$ELSE}
{$IFDEF USE_clock_gettime}
// TODO: use CLOCK_BOOTTIME on platforms that support it? It takes system
// suspension into account, whereas CLOCK_MONOTONIC does not...
clock_gettime(CLOCK_MONOTONIC, ts);
{$IFOPT R+} // detect range checking
{$R-}
{$DEFINE _RPlusWasEnabled}
{$ENDIF}
{$IFOPT Q+} // detect overflow checking
{$Q-}
{$DEFINE _QPlusWasEnabled}
{$ENDIF}
Result := (Int64(ts.tv_sec) * 1000) + (ts.tv_nsec div 1000000);
{$IFDEF _QPlusWasEnabled}
{$Q+}
{$UNDEF _QPlusWasEnabled}
{$ENDIF}
{$IFDEF _RPlusWasEnabled}
{$R+}
{$UNDEF _RPlusWasEnabled}
{$ENDIF}
{$ELSE}
{$IFDEF USE_BASEUNIX}
fpgettimeofday(@tv,nil);
{$ENDIF}
{$IFDEF KYLIXCOMPAT}
gettimeofday(tv, nil);
{$ENDIF}
{$IFOPT R+} // detect range checking
{$R-}
{$DEFINE _RPlusWasEnabled}
{$ENDIF}
Result := (Int64(tv.tv_sec) * 1000) + (tv.tv_usec div 1000);
{$IFDEF _RPlusWasEnabled}
{$R+}
{$UNDEF _RPlusWasEnabled}
{$ENDIF}
{
I've implemented this correctly for now. I'll argue for using
an int64 internally, since apparently quite some functionality
(throttle, etc etc) depends on it, and this value may wrap
at any point in time.
For Windows: Uptime > 72 hours isn't really that rare any more,
For Linux: no control over when this wraps.
IdEcho has code to circumvent the wrap, but its not very good
to have code for that at all spots where it might be relevant.
}
{$ENDIF}
{$ENDIF}
{$ENDIF}
{$IFDEF WINDOWS}
// S.G. 27/11/2002: Changed to use high-performance counters as per suggested
// S.G. 27/11/2002: by David B. Ferguson (david.mcs@ns.sympatico.ca)
// RLebeau 11/12/2009: removed the high-performance counters again. They
// are not reliable on multi-core systems, and are now starting to cause
// problems with TIdIOHandler.ReadLn() timeouts under Windows XP SP3, both
// 32-bit and 64-bit. Refer to these discussions:
//
// http://www.virtualdub.org/blog/pivot/entry.php?id=106
// http://blogs.msdn.com/oldnewthing/archive/2008/09/08/8931563.aspx
{$IFDEF USE_HI_PERF_COUNTER_FOR_TICKS}
{$IFDEF WINCE}
if Windows.QueryPerformanceCounter(@nTime) then begin
if Windows.QueryPerformanceFrequency(@freq) then begin
Result := Trunc((nTime.QuadPart / Freq.QuadPart) * 1000) and High(TIdTicks);
Exit;
end;
end;
{$ELSE}
if Windows.QueryPerformanceCounter(nTime) then begin
if Windows.QueryPerformanceFrequency(freq) then begin
Result := Trunc((nTime / Freq) * 1000) and High(TIdTicks);
Exit;
end;
end;
{$ENDIF}
{$ENDIF}
Result := TIdTicks(GetTickCount64());
{$ENDIF}
{$IFDEF DOTNET}
// Must cast to a cardinal
//
// http://lists.ximian.com/archives/public/mono-bugs/2003-November/009293.html
// Other references in Google.
// Bug in .NET. It acts like Win32, not as per .NET docs but goes negative after 25 days.
//
// There may be a problem in the future if .NET changes this to work as docced with 25 days.
// Will need to check our routines then and somehow counteract / detect this.
// One possibility is that we could just wrap it ourselves in this routine.
// TODO: use DateTime.Ticks instead?
//Result := DateTime.Now.Ticks div 10000;
Result := TIdTicks(Environment.TickCount);
{$ENDIF}
end;
{$I IdDeprecatedImplBugOff.inc}
function GetTickDiff(const AOldTickCount, ANewTickCount: UInt32): UInt32;
{$I IdDeprecatedImplBugOn.inc}
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
{This is just in case the TickCount rolled back to zero}
if ANewTickCount >= AOldTickCount then begin
Result := ANewTickCount - AOldTickCount;
end else begin
Result := ((High(UInt32) - AOldTickCount) + ANewTickCount) + 1;
end;
end;
function GetTickDiff64(const AOldTickCount, ANewTickCount: TIdTicks): TIdTicks;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
{This is just in case the TickCount rolled back to zero}
if ANewTickCount >= AOldTickCount then begin
Result := TIdTicks(ANewTickCount - AOldTickCount);
end else begin
Result := TIdTicks(((High(TIdTicks) - AOldTickCount) + ANewTickCount) + 1);
end;
end;
function GetElapsedTicks(const AOldTickCount: TIdTicks): UInt32;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Result := UInt32(GetTickDiff64(AOldTickCount, Ticks64));
end;
function GetElapsedTicks64(const AOldTickCount: TIdTicks): TIdTicks;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Result := GetTickDiff64(AOldTickCount, Ticks64);
end;
{$IFNDEF DOTNET}
function ServicesFilePath: string;
var
{$IFDEF WINDOWS}
sLocation: {$IFDEF STRING_UNICODE_MISMATCH}TIdPlatformString{$ELSE}string{$ENDIF};
{$ELSE}
sLocation: string;
{$ENDIF}
begin
{$IFDEF UNIX}
sLocation := '/etc/'; // assume Berkeley standard placement {do not localize}
{$ENDIF}
{$IFDEF WINDOWS}
{$IFNDEF WINCE}
SetLength(sLocation, MAX_PATH);
SetLength(sLocation, GetWindowsDirectory(
{$IFDEF STRING_UNICODE_MISMATCH}PIdPlatformChar(sLocation){$ELSE}PChar(sLocation){$ENDIF}
, MAX_PATH));
sLocation := IndyIncludeTrailingPathDelimiter(sLocation);
if IndyWindowsPlatform = VER_PLATFORM_WIN32_NT then begin
sLocation := sLocation + 'system32\drivers\etc\'; {do not localize}
end;
{$ELSE}
// GetWindowsDirectory() does not exist in WinCE, and there is no system folder, either
sLocation := '\Windows\'; {do not localize}
{$ENDIF}
{$ENDIF}
Result := sLocation + 'services'; {do not localize}
end;
{$ENDIF}
{$IFNDEF DOTNET}
// IdPorts returns a list of defined ports in /etc/services
function IdPorts: TIdPortList;
var
s: string;
idx, iPosSlash: {$IFDEF BYTE_COMPARE_SETS}Byte{$ELSE}Integer{$ENDIF};
i: {$IFDEF HAS_GENERICS_TList}Integer{$ELSE}PtrInt{$ENDIF};
iPrev: PtrInt;
sl: TStringList;
begin
if GIdPorts = nil then
begin
GIdPorts := TIdPortList.Create;
sl := TStringList.Create;
try
// TODO: use TStreamReader instead, on versions that support it
sl.LoadFromFile(ServicesFilePath); {do not localize}
iPrev := 0;
for idx := 0 to sl.Count - 1 do
begin
s := sl[idx];
iPosSlash := IndyPos('/', s); {do not localize}
if (iPosSlash > 0) and (not (IndyPos('#', s) in [1..iPosSlash])) then {do not localize}
begin // presumably found a port number that isn't commented {Do not Localize}
i := iPosSlash;
repeat
Dec(i);
if i = 0 then begin
raise EIdCorruptServicesFile.CreateFmt(RSCorruptServicesFile, [ServicesFilePath]); {do not localize}
end;
//TODO: Make Whitespace a function to elim warning
until Ord(s[i]) in IdWhiteSpace;
i := IndyStrToInt(Copy(s, i+1, iPosSlash-i-1));
if i <> iPrev then begin
GIdPorts.Add(
{$IFDEF HAS_GENERICS_TList}i{$ELSE}Pointer(i){$ENDIF}
);
end;
iPrev := i;
end;
end;
finally
sl.Free;
end;
end;
Result := GIdPorts;
end;
{$ENDIF}
function iif(ATest: Boolean; const ATrue: Integer; const AFalse: Integer): Integer;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
if ATest then begin
Result := ATrue;
end else begin
Result := AFalse;
end;
end;
function iif(ATest: Boolean; const ATrue: string; const AFalse: string): string;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
if ATest then begin
Result := ATrue;
end else begin
Result := AFalse;
end;
end;
function iif(ATest: Boolean; const ATrue: Boolean; const AFalse: Boolean): Boolean;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
if ATest then begin
Result := ATrue;
end else begin
Result := AFalse;
end;
end;
function iif(const AEncoding, ADefEncoding: IIdTextEncoding; ADefEncodingType: IdTextEncodingType = encASCII): IIdTextEncoding;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Result := AEncoding;
if Result = nil then
begin
Result := ADefEncoding;
EnsureEncoding(Result, ADefEncodingType);
end;
end;
function InMainThread: Boolean;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
{$IFDEF DOTNET}
Result := System.Threading.Thread.CurrentThread = MainThread;
{$ELSE}
Result := GetCurrentThreadID = MainThreadID;
{$ENDIF}
end;
procedure WriteMemoryStreamToStream(Src: TMemoryStream; Dest: TStream; Count: TIdStreamSize);
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
{$IFDEF DOTNET}
Dest.Write(Src.Memory, Count);
{$ELSE}
Dest.Write(Src.Memory^, Count);
{$ENDIF}
end;
{$IFNDEF DOTNET_EXCLUDE}
function IsCurrentThread(AThread: TThread): Boolean;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Result := AThread.ThreadID = GetCurrentThreadID;
end;
{$ENDIF}
//convert a dword into an IPv4 address in dotted form
function MakeUInt32IntoIPv4Address(const ADWord: UInt32): string;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Result := IntToStr((ADWord shr 24) and $FF) + '.';
Result := Result + IntToStr((ADWord shr 16) and $FF) + '.';
Result := Result + IntToStr((ADWord shr 8) and $FF) + '.';
Result := Result + IntToStr(ADWord and $FF);
end;
{$I IdDeprecatedImplBugOff.inc}
function MakeDWordIntoIPv4Address(const ADWord: UInt32): string;
{$I IdDeprecatedImplBugOn.inc}
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Result := MakeUInt32IntoIPv4Address(ADWord);
end;
function IsAlpha(const AChar: Char): Boolean;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
// TODO: under XE3.5+, use TCharHelper.IsLetter() instead
// TODO: under D2009+, use TCharacter.IsLetter() instead
// Do not use IsCharAlpha or IsCharAlphaNumeric - they are Win32 routines
Result := ((AChar >= 'a') and (AChar <= 'z')) or ((AChar >= 'A') and (AChar <= 'Z')); {Do not Localize}
end;
function IsAlpha(const AString: String; const ALength: Integer = -1; const AIndex: Integer = 1): Boolean;
{$IFDEF USE_INLINE}inline;{$ENDIF}
var
i: Integer;
LLen: Integer;
begin
Result := False;
LLen := IndyLength(AString, ALength, AIndex);
if LLen > 0 then begin
for i := 0 to LLen-1 do begin
if not IsAlpha(AString[AIndex+i]) then begin
Exit;
end;
end;
Result := True;
end;
end;
function IsAlphaNumeric(const AChar: Char): Boolean;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
// Do not use IsCharAlpha or IsCharAlphaNumeric - they are Win32 routines
Result := IsAlpha(AChar) or IsNumeric(AChar);
end;
function IsAlphaNumeric(const AString: String; const ALength: Integer = -1; const AIndex: Integer = 1): Boolean;
{$IFDEF USE_INLINE}inline;{$ENDIF}
var
i: Integer;
LLen: Integer;
begin
Result := False;
LLen := IndyLength(AString, ALength, AIndex);
if LLen > 0 then begin
for i := 0 to LLen-1 do begin
if not IsAlphaNumeric(AString[AIndex+i]) then begin
Exit;
end;
end;
Result := True;
end;
end;
function IsOctal(const AChar: Char): Boolean; overload;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Result := (AChar >= '0') and (AChar <= '7') {Do not Localize}
end;
function IsOctal(const AString: string; const ALength: Integer = -1; const AIndex: Integer = 1): Boolean; overload;
{$IFDEF USE_INLINE}inline;{$ENDIF}
var
i: Integer;
LLen: Integer;
begin
Result := False;
LLen := IndyLength(AString, ALength, AIndex);
if LLen > 0 then begin
for i := 0 to LLen-1 do begin
if not IsOctal(AString[AIndex+i]) then begin
Exit;
end;
end;
Result := True;
end;
end;
function IsHexidecimal(const AChar: Char): Boolean; overload;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Result := IsNumeric(AChar)
or ((AChar >= 'A') and (AChar <= 'F')) {Do not Localize}
or ((AChar >= 'a') and (AChar <= 'f')); {Do not Localize}
end;
function IsHexidecimal(const AString: string; const ALength: Integer = -1; const AIndex: Integer = 1): Boolean; overload;
{$IFDEF USE_INLINE}inline;{$ENDIF}
var
i: Integer;
LLen: Integer;
begin
Result := False;
LLen := IndyLength(AString, ALength, AIndex);
if LLen > 0 then begin
for i := 0 to LLen-1 do begin
if not IsHexidecimal(AString[AIndex+i]) then begin
Exit;
end;
end;
Result := True;
end;
end;
{$HINTS OFF}
function IsNumeric(const AString: string): Boolean;
var
LCode: Integer;
LVoid: Int64;
begin
Val(AString, LVoid, LCode);
Result := LCode = 0;
end;
{$HINTS ON}
function IsNumeric(const AString: string; const ALength: Integer; const AIndex: Integer = 1): Boolean;
var
I: Integer;
LLen: Integer;
begin
Result := False;
LLen := IndyLength(AString, ALength, AIndex);
if LLen > 0 then begin
for I := 0 to LLen-1 do begin
if not IsNumeric(AString[AIndex+i]) then begin
Exit;
end;
end;
Result := True;
end;
end;
function IsNumeric(const AChar: Char): Boolean;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
// TODO: under XE3.5+, use TCharHelper.IsDigit() instead
// TODO: under D2009+, use TCharacter.IsDigit() instead
// Do not use IsCharAlpha or IsCharAlphaNumeric - they are Win32 routines
Result := (AChar >= '0') and (AChar <= '9'); {Do not Localize}
end;
{
This is an adaptation of the StrToInt64 routine in SysUtils.
We had to adapt it to work with Int64 because the one with Integers
can not deal with anything greater than MaxInt and IP addresses are
always $0-$FFFFFFFF (unsigned)
}
{$IFNDEF HAS_StrToInt64Def}
function StrToInt64Def(const S: string; const Default: Integer): Int64;
{$IFDEF USE_INLINE}inline;{$ENDIF}
var
E: Integer;
begin
Val(S, Result, E);
if E <> 0 then begin
Result := Default;
end;
end;
{$ENDIF}
function IPv4MakeUInt32InRange(const AInt: Int64; const A256Power: Integer): UInt32;
{$IFDEF USE_INLINE}inline;{$ENDIF}
//Note that this function is only for stripping off some extra bits
//from an address that might appear in some spam E-Mails.
begin
case A256Power of
4: Result := (AInt and POWER_4);
3: Result := (AInt and POWER_3);
2: Result := (AInt and POWER_2);
else
Result := (AInt and POWER_1);
end;
end;
{$I IdDeprecatedImplBugOff.inc}
function IPv4MakeLongWordInRange(const AInt: Int64; const A256Power: Integer): UInt32;
{$I IdDeprecatedImplBugOn.inc}
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Result := IPv4MakeUInt32InRange(AInt, A256Power);
end;
function IPv4ToUInt32(const AIPAddress: string): UInt32;
{$IFDEF USE_INLINE}inline;{$ENDIF}
var
LErr: Boolean;
begin
Result := IPv4ToUInt32(AIPAddress, LErr);
end;
{$I IdDeprecatedImplBugOff.inc}
function IPv4ToDWord(const AIPAddress: string): UInt32; overload;
{$I IdDeprecatedImplBugOn.inc}
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Result := IPv4ToUInt32(AIPAddress);
end;
function IPv4ToUInt32(const AIPAddress: string; var VErr: Boolean): UInt32;
var
{$IFDEF DOTNET}
AIPaddr: IPAddress;
{$ELSE}
LBuf, LBuf2: string;
L256Power: Integer;
LParts: Integer; //how many parts should we process at a time
{$ENDIF}
begin
VErr := True;
Result := 0;
{$IFDEF DOTNET}
AIPaddr := System.Net.IPAddress.Parse(AIPAddress);
try
try
if AIPaddr.AddressFamily = Addressfamily.InterNetwork then begin
{$IFDEF DOTNET_2_OR_ABOVE}
//This looks funny but it's just to circvument a warning about
//a depreciated property in AIPaddr. We can safely assume
//this is an IPv4 address.
Result := BytesToUInt32( AIPAddr.GetAddressBytes,0);
{$ENDIF}
{$IFDEF DOTNET_1_1}
Result := AIPaddr.Address;
{$ENDIF}
VErr := False;
end;
except
VErr := True;
end;
finally
FreeAndNil(AIPaddr);
end;
{$ELSE}
// S.G. 11/8/2003: Added overflow checking disabling and change multiplys by SHLs.
// Locally disable overflow checking so we can safely use SHL and SHR
{$IFOPT Q+} // detect overflow checking
{$DEFINE _QPlusWasEnabled}
{$Q-}
{$ENDIF}
L256Power := 4;
LBuf2 := AIPAddress;
repeat
LBuf := Fetch(LBuf2, '.');
if LBuf = '' then begin
Break;
end;
//We do things this way because we have to treat
//IP address parts differently than a whole number
//and sometimes, there can be missing periods.
if (LBuf2 = '') and (L256Power > 1) then begin
LParts := L256Power;
Result := Result shl (L256Power SHL 3);
end else begin
LParts := 1;
Result := Result shl 8;
end;
if TextStartsWith(LBuf, IdHexPrefix) then begin
//this is a hexideciaml number
if not IsHexidecimal(Copy(LBuf, 3, MaxInt)) then begin
Exit;
end;
Result := Result + IPv4MakeUInt32InRange(StrToInt64Def(LBuf, 0), LParts);
end else begin
if not IsNumeric(LBuf) then begin
//There was an error meaning an invalid IP address
Exit;
end;
if TextStartsWith(LBuf, '0') and IsOctal(LBuf) then begin {do not localize}
//this is octal
Result := Result + IPv4MakeUInt32InRange(OctalToInt64(LBuf), LParts);
end else begin
//this must be a decimal
Result := Result + IPv4MakeUInt32InRange(StrToInt64Def(LBuf, 0), LParts);
end;
end;
Dec(L256Power);
until False;
VErr := False;
// Restore overflow checking
{$IFDEF _QPlusWasEnabled} // detect previous setting
{$UNDEF _QPlusWasEnabled}
{$Q+}
{$ENDIF}
{$ENDIF}
end;
{$I IdDeprecatedImplBugOff.inc}
function IPv4ToDWord(const AIPAddress: string; var VErr: Boolean): UInt32;
{$I IdDeprecatedImplBugOn.inc}
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Result := IPv4ToUInt32(AIPAddress, VErr);
end;
function IPv6AddressToStr(const AValue: TIdIPv6Address): string;
{$IFDEF USE_INLINE}inline;{$ENDIF}
var
i: Integer;
begin
Result := IntToHex(AValue[0], 4);
for i := 1 to 7 do begin
Result := Result + ':' + IntToHex(AValue[i], 4);
end;
end;
function MakeCanonicalIPv4Address(const AAddr: string): string;
{$IFDEF USE_INLINE}inline;{$ENDIF}
var
LErr: Boolean;
LIP: UInt32;
begin
LIP := IPv4ToUInt32(AAddr, LErr);
if LErr then begin
Result := '';
end else begin
Result := MakeUInt32IntoIPv4Address(LIP);
end;
end;
function MakeCanonicalIPv6Address(const AAddr: string): string;
// return an empty string if the address is invalid,
// for easy checking if its an address or not.
var
p, i: Integer;
{$IFDEF BYTE_COMPARE_SETS}
dots, colons: Byte;
{$ELSE}
dots, colons: Integer;
{$ENDIF}
colonpos: array[1..8] of Integer;
dotpos: array[1..3] of Integer;
LAddr: string;
num: Integer;
haddoublecolon: boolean;
fillzeros: Integer;
begin
Result := ''; // error
LAddr := AAddr;
if Length(LAddr) = 0 then begin
Exit;
end;
if TextStartsWith(LAddr, ':') then begin
LAddr := '0' + LAddr;
end;
if TextEndsWith(LAddr, ':') then begin
LAddr := LAddr + '0';
end;
dots := 0;
colons := 0;
for p := 1 to Length(LAddr) do begin
case LAddr[p] of
'.': begin
Inc(dots);
if dots < 4 then begin
dotpos[dots] := p;
end else begin
Exit; // error in address
end;
end;
':': begin
Inc(colons);
if colons < 8 then begin
colonpos[colons] := p;
end else begin
Exit; // error in address
end;
end;
'a'..'f',
'A'..'F': if dots > 0 then Exit;
// allow only decimal stuff within dotted portion, ignore otherwise
'0'..'9': ; // do nothing
else
Exit; // error in address
end; // case
end; // for
if not (dots in [0,3]) then begin
Exit; // you have to write 0 or 3 dots...
end;
if dots = 3 then begin
if not (colons in [2..6]) then begin
Exit; // must not have 7 colons if we have dots
end;
if colonpos[colons] > dotpos[1] then begin
Exit; // x:x:x.x:x:x is not valid
end;
end else begin
if not (colons in [2..7]) then begin
Exit; // must at least have two colons
end;
end;
// now start :-)
num := IndyStrToInt('$'+Copy(LAddr, 1, colonpos[1]-1), -1);
if (num < 0) or (num > 65535) then begin
Exit; // huh? odd number...
end;
Result := IntToHex(num, 1) + ':';
haddoublecolon := False;
for p := 2 to colons do begin
if colonpos[p - 1] = colonpos[p]-1 then begin
if haddoublecolon then begin
Result := '';
Exit; // only a single double-dot allowed!
end;
haddoublecolon := True;
fillzeros := 8 - colons;
if dots > 0 then begin
Dec(fillzeros);
end;
for i := 1 to fillzeros do begin
Result := Result + '0:'; {do not localize}
end;
end else begin
num := IndyStrToInt('$' + Copy(LAddr, colonpos[p - 1] + 1, colonpos[p] - colonpos[p - 1] - 1), -1);
if (num < 0) or (num > 65535) then begin
Result := '';
Exit; // huh? odd number...
end;
Result := Result + IntToHex(num,1) + ':';
end;
end; // end of colon separated part
if dots = 0 then begin
num := IndyStrToInt('$' + Copy(LAddr, colonpos[colons] + 1, MaxInt), -1);
if (num < 0) or (num > 65535) then begin
Result := '';
Exit; // huh? odd number...
end;
Result := Result + IntToHex(num,1) + ':';
end;
if dots > 0 then begin
num := IndyStrToInt(Copy(LAddr, colonpos[colons] + 1, dotpos[1] - colonpos[colons] -1),-1);
if (num < 0) or (num > 255) then begin
Result := '';
Exit;
end;
Result := Result + IntToHex(num, 2);
num := IndyStrToInt(Copy(LAddr, dotpos[1]+1, dotpos[2]-dotpos[1]-1),-1);
if (num < 0) or (num > 255) then begin
Result := '';
Exit;
end;
Result := Result + IntToHex(num, 2) + ':';
num := IndyStrToInt(Copy(LAddr, dotpos[2] + 1, dotpos[3] - dotpos[2] -1),-1);
if (num < 0) or (num > 255) then begin
Result := '';
Exit;
end;
Result := Result + IntToHex(num, 2);
num := IndyStrToInt(Copy(LAddr, dotpos[3] + 1, 3), -1);
if (num < 0) or (num > 255) then begin
Result := '';
Exit;
end;
Result := Result + IntToHex(num, 2) + ':';
end;
SetLength(Result, Length(Result) - 1);
end;
procedure IPv6ToIdIPv6Address(const AIPAddress: String; var VAddress: TIdIPv6Address);
{$IFDEF USE_INLINE}inline;{$ENDIF}
var
LErr: Boolean;
begin
IPv6ToIdIPv6Address(AIPAddress, VAddress, LErr);
if LErr then begin
raise EIdInvalidIPv6Address.CreateFmt(RSInvalidIPv6Address, [AIPAddress]);
end;
end;
procedure IPv6ToIdIPv6Address(const AIPAddress: String; var VAddress: TIdIPv6Address; var VErr: Boolean);
var
LAddress: string;
I: Integer;
begin
LAddress := MakeCanonicalIPv6Address(AIPAddress);
VErr := (LAddress = '');
if VErr then begin
Exit;
end;
for I := 0 to 7 do begin
VAddress[I] := IndyStrToInt('$' + Fetch(LAddress,':'), 0);
end;
end;
function IndyMax(const AValueOne, AValueTwo: Int64): Int64;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
if AValueOne < AValueTwo then begin
Result := AValueTwo;
end else begin
Result := AValueOne;
end;
end;
function IndyMax(const AValueOne, AValueTwo: Int32): Int32;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
if AValueOne < AValueTwo then begin
Result := AValueTwo;
end else begin
Result := AValueOne;
end;
end;
function IndyMax(const AValueOne, AValueTwo: UInt16): UInt16;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
if AValueOne < AValueTwo then begin
Result := AValueTwo;
end else begin
Result := AValueOne;
end;
end;
{$IFNDEF DOTNET}
// TODO: validate this with Unicode data
function MemoryPos(const ASubStr: string; MemBuff: PChar; MemorySize: Integer): Integer;
var
LSearchLength: Integer;
LS1: Integer;
LChar: Char;
LPS, LPM: PChar;
begin
LSearchLength := Length(ASubStr);
if (LSearchLength = 0) or (LSearchLength > (MemorySize * SizeOf(Char))) then begin
Result := 0;
Exit;
end;
LChar := PChar(Pointer(ASubStr))^; //first char
LPS := PChar(Pointer(ASubStr))+1;//tail string
LPM := MemBuff;
LS1 := LSearchLength-1;
LSearchLength := MemorySize-LS1;//MemorySize-LS+1
if LS1 = 0 then begin //optimization for freq used LF
while LSearchLength > 0 do begin
if LPM^ = LChar then begin
Result := LPM-MemBuff + 1;
Exit;
end;
Inc(LPM);
Dec(LSearchLength);
end;//while
end else begin
while LSearchLength > 0 do begin
if LPM^ = LChar then begin
Inc(LPM);
if CompareMem(LPM, LPS, LS1 * SizeOf(Char)) then begin
Result := LPM - MemBuff;
Exit;
end;
end else begin
Inc(LPM);
end;
Dec(LSearchLength);
end;
end;
Result := 0;
end;
{$ENDIF}
function IndyMin(const AValueOne, AValueTwo: Int32): Int32;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
if AValueOne > AValueTwo then begin
Result := AValueTwo;
end else begin
Result := AValueOne;
end;
end;
function IndyMin(const AValueOne, AValueTwo: Int64): Int64;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
if AValueOne > AValueTwo then begin
Result := AValueTwo;
end else begin
Result := AValueOne;
end;
end;
function IndyMin(const AValueOne, AValueTwo: UInt16): UInt16;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
if AValueOne > AValueTwo then begin
Result := AValueTwo;
end else begin
Result := AValueOne;
end;
end;
function PosIdx(const ASubStr, AStr: string; AStartPos: UInt32): UInt32;
{$IFDEF DOTNET}
{$IFDEF USE_INLINE}inline;{$ENDIF}
{$ELSE}
// use best register allocation on Win32
function FindStr(ALStartPos, EndPos: UInt32; StartChar: Char; const ALStr: string): UInt32;
begin
for Result := ALStartPos to EndPos do begin
if ALStr[Result] = StartChar then begin
Exit;
end;
end;
Result := 0;
end;
// use best register allocation on Win32
function FindNextStr(ALStartPos, EndPos: UInt32; const ALStr, ALSubStr: string): UInt32;
begin
for Result := ALStartPos + 1 to EndPos do begin
if ALStr[Result] <> ALSubStr[Result - ALStartPos + 1] then begin
Exit;
end;
end;
Result := 0;
end;
var
StartChar: Char;
LenSubStr, LenStr: UInt32;
EndPos: UInt32;
{$ENDIF}
begin
if AStartPos = 0 then begin
AStartPos := 1;
end;
{$IFDEF DOTNET}
Result := AStr.IndexOf(ASubStr, AStartPos-1) + 1;
{$ELSE}
Result := 0;
LenSubStr := Length(ASubStr);
LenStr := Length(AStr);
if (LenSubStr = 0) or (AStr = '') or (LenSubStr > (LenStr - (AStartPos - 1))) then begin
Exit;
end;
StartChar := ASubStr[1];
EndPos := LenStr - LenSubStr + 1;
if LenSubStr = 1 then begin
Result := FindStr(AStartPos, EndPos, StartChar, AStr)
end else
begin
repeat
Result := FindStr(AStartPos, EndPos, StartChar, AStr);
if Result = 0 then begin
Break;
end;
AStartPos := Result;
Result := FindNextStr(Result, AStartPos + LenSubStr - 1, AStr, ASubStr);
if Result = 0 then
begin
Result := AStartPos;
Exit;
end;
Inc(AStartPos);
until False;
end;
{$ENDIF}
end;
function SBPos(const Substr, S: string): Integer;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
// Necessary because of "Compiler magic"
Result := Pos(Substr, S);
end;
{$IFNDEF DOTNET}
function SBStrScan(Str: PChar; Chr: Char): PChar;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Result := SysUtils.StrScan(Str, Chr);
end;
{$ENDIF}
{$IFNDEF DOTNET}
//Don't rename this back to AnsiPos because that conceals a symbol in Windows
function InternalAnsiPos(const Substr, S: string): Integer;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Result := SysUtils.AnsiPos(Substr, S);
end;
function InternalAnsiStrScan(Str: PChar; Chr: Char): PChar;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Result := SysUtils.AnsiStrScan(Str, Chr);
end;
{$ENDIF}
procedure IndySetThreadPriority(AThread: TThread; const APriority: TIdThreadPriority;
const APolicy: Integer = -MaxInt);
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
{$IFDEF UNIX}
{$IFDEF KYLIXCOMPAT}
{$IFDEF INT_THREAD_PRIORITY}
// Linux only allows root to adjust thread priorities, so we just ignore this call in Linux?
// actually, why not allow it if root
// and also allow setting *down* threadpriority (anyone can do that)
// note that priority is called "niceness" and positive is lower priority
if (getpriority(PRIO_PROCESS, 0) < APriority) or (geteuid = 0) then begin
setpriority(PRIO_PROCESS, 0, APriority);
end;
{$ELSE}
AThread.Priority := APriority;
{$ENDIF}
{$ENDIF}
{$IFDEF USE_BASEUNIX}
// Linux only allows root to adjust thread priorities, so we just ingnore this call in Linux?
// actually, why not allow it if root
// and also allow setting *down* threadpriority (anyone can do that)
// note that priority is called "niceness" and positive is lower priority
if (fpgetpriority(PRIO_PROCESS, 0) < cint(APriority)) or (fpgeteuid = 0) then begin
fpsetpriority(PRIO_PROCESS, 0, cint(APriority));
end;
{$ENDIF}
{$ENDIF}
{$IFDEF WINDOWS}
AThread.Priority := APriority;
{$ENDIF}
{$IFDEF DOTNET}
AThread.Priority := APriority;
{$ENDIF}
end;
procedure IndySleep(ATime: UInt32);
{$IFDEF USE_VCL_POSIX}
{$IFDEF USE_INLINE}inline;{$ENDIF}
var
LTime: TimeVal;
{$ELSE}
{$IFNDEF UNIX}
{$IFDEF USE_INLINE}inline;{$ENDIF}
{$ELSE}
var
LTime: TTimeVal;
{$ENDIF}
{$ENDIF}
begin
{$IFDEF UNIX}
// *nix: Is there are reason for not using nanosleep?
// what if the user just calls sleep? without doing anything...
// cannot use GStack.WSSelectRead(nil, ATime)
// since no readsocketlist exists to get the fdset
LTime.tv_sec := ATime div 1000;
LTime.tv_usec := (ATime mod 1000) * 1000;
{$IFDEF USE_VCL_POSIX}
select( 0, nil, nil, nil, @LTime);
{$ENDIF}
{$IFDEF KYLIXCOMPAT}
Libc.Select(0, nil, nil, nil, @LTime);
{$ENDIF}
{$IFDEF USE_BASEUNIX}
fpSelect(0, nil, nil, nil, @LTime);
{$ENDIF}
{$ENDIF}
{$IFDEF WINDOWS}
Windows.Sleep(ATime);
{$ENDIF}
{$IFDEF DOTNET}
Thread.Sleep(ATime);
{$ENDIF}
end;
{$I IdDeprecatedImplBugOff.inc}
procedure SplitColumnsNoTrim(const AData: string; AStrings: TStrings; const ADelim: string = ' ');
{$I IdDeprecatedImplBugOn.inc}
begin
SplitDelimitedString(AData, AStrings, False, ADelim{$IFNDEF USE_OBJECT_ARC}, True{$ENDIF});
end;
{$I IdDeprecatedImplBugOff.inc}
procedure SplitColumns(const AData: string; AStrings: TStrings; const ADelim: string = ' ');
{$I IdDeprecatedImplBugOn.inc}
begin
SplitDelimitedString(AData, AStrings, True, ADelim{$IFNDEF USE_OBJECT_ARC}, True{$ENDIF});
end;
procedure SplitDelimitedString(const AData: string; AStrings: TStrings; ATrim: Boolean;
const ADelim: string = ' '{$IFNDEF USE_OBJECT_ARC}; AIncludePositions: Boolean = False{$ENDIF});
var
i: Integer;
LData: string;
LDelim: Integer; //delim len
LLeft: string;
LLastPos, LLeadingSpaceCnt: PtrInt;
begin
Assert(Assigned(AStrings));
AStrings.Clear;
LDelim := Length(ADelim);
LLastPos := 1;
if ATrim then begin
LData := Trim(AData);
if LData = '' then begin //if WhiteStr
Exit;
end;
LLeadingSpaceCnt := 0;
while AData[LLeadingSpaceCnt + 1] <= #32 do begin
Inc(LLeadingSpaceCnt);
end;
i := Pos(ADelim, LData);
while I > 0 do begin
LLeft := Copy(LData, LLastPos, I - LLastPos); //'abc d' len:=i(=4)-1 {Do not Localize}
if LLeft > '' then begin {Do not Localize}
{$IFNDEF USE_OBJECT_ARC}
if AIncludePositions then begin
AStrings.AddObject(Trim(LLeft), TObject(LLastPos + LLeadingSpaceCnt));
end else
{$ENDIF}
begin
AStrings.Add(Trim(LLeft));
end;
end;
LLastPos := I + LDelim; //first char after Delim
i := PosIdx(ADelim, LData, LLastPos);
end;//while found
if LLastPos <= Length(LData) then begin
{$IFNDEF USE_OBJECT_ARC}
if AIncludePositions then begin
AStrings.AddObject(Trim(Copy(LData, LLastPos, MaxInt)), TObject(LLastPos + LLeadingSpaceCnt));
end else
{$ENDIF}
begin
AStrings.Add(Trim(Copy(LData, LLastPos, MaxInt)));
end;
end;
end else
begin
i := Pos(ADelim, AData);
while I > 0 do begin
LLeft := Copy(AData, LLastPos, I - LLastPos); //'abc d' len:=i(=4)-1 {Do not Localize}
if LLeft <> '' then begin {Do not Localize}
{$IFNDEF USE_OBJECT_ARC}
if AIncludePositions then begin
AStrings.AddObject(LLeft, TObject(LLastPos));
end else
{$ENDIF}
begin
AStrings.Add(LLeft);
end;
end;
LLastPos := I + LDelim; //first char after Delim
i := PosIdx(ADelim, AData, LLastPos);
end;
if LLastPos <= Length(AData) then begin
{$IFNDEF USE_OBJECT_ARC}
if AIncludePositions then begin
AStrings.AddObject(Copy(AData, LLastPos, MaxInt), TObject(LLastPos));
end else
{$ENDIF}
begin
AStrings.Add(Copy(AData, LLastPos, MaxInt));
end;
end;
end;
end;
{$IFDEF USE_OBJECT_ARC}
constructor TIdStringPosition.Create(const AValue: String; const APosition: Integer);
begin
Value := AValue;
Position := APosition;
end;
procedure SplitDelimitedString(const AData: string; AStrings: TIdStringPositionList;
ATrim: Boolean; const ADelim: string = ' ');
var
i: Integer;
LData: string;
LDelim: Integer; //delim len
LLeft: string;
LLastPos, LLeadingSpaceCnt: Integer;
begin
Assert(Assigned(AStrings));
AStrings.Clear;
LDelim := Length(ADelim);
LLastPos := 1;
if ATrim then begin
LData := Trim(AData);
if LData = '' then begin //if WhiteStr
Exit;
end;
LLeadingSpaceCnt := 0;
while AData[LLeadingSpaceCnt + 1] <= #32 do begin
Inc(LLeadingSpaceCnt);
end;
i := Pos(ADelim, LData);
while I > 0 do begin
LLeft := Copy(LData, LLastPos, I - LLastPos); //'abc d' len:=i(=4)-1 {Do not Localize}
if LLeft > '' then begin {Do not Localize}
AStrings.Add(TIdStringPosition.Create(Trim(LLeft), LLastPos + LLeadingSpaceCnt));
end;
LLastPos := I + LDelim; //first char after Delim
i := PosIdx(ADelim, LData, LLastPos);
end;//while found
if LLastPos <= Length(LData) then begin
AStrings.Add(TIdStringPosition.Create(Trim(Copy(LData, LLastPos, MaxInt)), LLastPos + LLeadingSpaceCnt));
end;
end else
begin
i := Pos(ADelim, AData);
while I > 0 do begin
LLeft := Copy(AData, LLastPos, I - LLastPos); //'abc d' len:=i(=4)-1 {Do not Localize}
if LLeft <> '' then begin {Do not Localize}
AStrings.Add(TIdStringPosition.Create(LLeft, LLastPos));
end;
LLastPos := I + LDelim; //first char after Delim
i := PosIdx(ADelim, AData, LLastPos);
end;
if LLastPos <= Length(AData) then begin
AStrings.Add(TIdStringPosition.Create(Copy(AData, LLastPos, MaxInt), LLastPos));
end;
end;
end;
{$ENDIF}
{$IFDEF DOTNET}
procedure SetThreadName(const AName: string; AThread: System.Threading.Thread = nil);
begin
if AThread = nil then begin
AThread := System.Threading.Thread.CurrentThread;
end;
// cannot rename a previously-named thread
if AThread.Name = nil then begin
AThread.Name := AName;
end;
end;
{$ELSE}
procedure SetThreadName(const AName: string; AThreadID: UInt32 = $FFFFFFFF);
{$IFDEF HAS_NAMED_THREADS}
{$IFDEF HAS_TThread_NameThreadForDebugging}
{$IFDEF USE_INLINE}inline;{$ENDIF}
{$ELSE}
{$IFDEF WINDOWS}
const
MS_VC_EXCEPTION = $406D1388;
type
TThreadNameInfo = record
RecType: UInt32; // Must be 0x1000
Name: PAnsiChar; // Pointer to name (in user address space)
ThreadID: UInt32; // Thread ID (-1 indicates caller thread)
Flags: UInt32; // Reserved for future use. Must be zero
end;
var
{$IFDEF STRING_IS_UNICODE}
LName: AnsiString;
{$ENDIF}
LThreadNameInfo: TThreadNameInfo;
{$ENDIF}
{$ENDIF}
{$ENDIF}
begin
{$IFDEF HAS_NAMED_THREADS}
{$IFDEF HAS_TThread_NameThreadForDebugging}
TThread.NameThreadForDebugging(
{$IFDEF HAS_AnsiString}
AnsiString(AName) // explicit convert to Ansi
{$ELSE}
AName
{$ENDIF},
AThreadID
);
{$ELSE}
{$IFDEF WINDOWS}
{$IFDEF STRING_IS_UNICODE}
LName := AnsiString(AName); // explicit convert to Ansi
{$ENDIF}
LThreadNameInfo.RecType := $1000;
LThreadNameInfo.Name := PAnsiChar({$IFDEF STRING_IS_UNICODE}LName{$ELSE}AName{$ENDIF});
LThreadNameInfo.ThreadID := AThreadID;
LThreadNameInfo.Flags := 0;
try
// This is a wierdo Windows way to pass the info in
RaiseException(MS_VC_EXCEPTION, 0, SizeOf(LThreadNameInfo) div SizeOf(UInt32),
PDWord(@LThreadNameInfo));
except
end;
{$ENDIF}
{$ENDIF}
{$ELSE}
// Do nothing. No support in this compiler for it.
{$ENDIF}
end;
{$ENDIF}
{$IFDEF DOTNET}
{$IFNDEF DOTNET_2_OR_ABOVE}
{ TEvent }
constructor TEvent.Create(EventAttributes: IntPtr; ManualReset, InitialState: Boolean; const Name: string);
begin
inherited Create;
// Name not used
if ManualReset then begin
FEvent := ManualResetEvent.Create(InitialState);
end else begin
FEvent := AutoResetEvent.Create(InitialState);
end;
end;
constructor TEvent.Create;
begin
Create(nil, True, False, ''); {Do not Localize}
end;
destructor TEvent.Destroy;
begin
if Assigned(FEvent) then begin
FEvent.Close;
end;
FreeAndNil(FEvent);
inherited Destroy;
end;
procedure TEvent.SetEvent;
begin
if FEvent is ManualResetEvent then begin
ManualResetEvent(FEvent).&Set;
end else begin
AutoResetEvent(FEvent).&Set;
end;
end;
procedure TEvent.ResetEvent;
begin
if FEvent is ManualResetEvent then begin
ManualResetEvent(FEvent).Reset;
end else begin
AutoResetEvent(FEvent).Reset;
end;
end;
function TEvent.WaitFor(Timeout: UInt32): TWaitResult;
var
Passed: Boolean;
begin
try
if Timeout = INFINITE then begin
Passed := FEvent.WaitOne;
end else begin
Passed := FEvent.WaitOne(Timeout, True);
end;
if Passed then begin
Result := wrSignaled;
end else begin
Result := wrTimeout;
end;
except
Result := wrError;
end;
end;
{ TCriticalSection }
procedure TCriticalSection.Acquire;
begin
Enter;
end;
procedure TCriticalSection.Release;
begin
Leave;
end;
function TCriticalSection.TryEnter: Boolean;
begin
Result := System.Threading.Monitor.TryEnter(Self);
end;
procedure TCriticalSection.Enter;
begin
System.Threading.Monitor.Enter(Self);
end;
procedure TCriticalSection.Leave;
begin
System.Threading.Monitor.Exit(Self);
end;
{$ENDIF}
{$ENDIF}
{ TIdLocalEvent }
constructor TIdLocalEvent.Create(const AInitialState: Boolean = False; const AManualReset: Boolean = False);
begin
inherited Create(nil, AManualReset, AInitialState, ''); {Do not Localize}
end;
function TIdLocalEvent.WaitForEver: TWaitResult;
begin
Result := WaitFor(Infinite);
end;
procedure ToDo(const AMsg: string);
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
raise EIdException.Create(AMsg);
end;
// RLebeau: the following three functions are utility functions
// that determine the usable amount of data in various buffer types.
// There are many operations in Indy that allow the user to specify
// data sizes, or to have Indy calculate it. So these functions
// help reduce code duplication.
function IndyLength(const ABuffer: String; const ALength: Integer = -1; const AIndex: Integer = 1): Integer;
{$IFDEF USE_INLINE}inline;{$ENDIF}
var
LAvailable: Integer;
begin
Assert(AIndex >= 1);
LAvailable := IndyMax(Length(ABuffer)-AIndex+1, 0);
if ALength < 0 then begin
Result := LAvailable;
end else begin
Result := IndyMin(LAvailable, ALength);
end;
end;
function IndyLength(const ABuffer: TIdBytes; const ALength: Integer = -1; const AIndex: Integer = 0): Integer;
{$IFDEF USE_INLINE}inline;{$ENDIF}
var
LAvailable: Integer;
begin
Assert(AIndex >= 0);
LAvailable := IndyMax(Length(ABuffer)-AIndex, 0);
if ALength < 0 then begin
Result := LAvailable;
end else begin
Result := IndyMin(LAvailable, ALength);
end;
end;
function IndyLength(const ABuffer: TStream; const ALength: TIdStreamSize = -1): TIdStreamSize; overload;
{$IFDEF USE_INLINE}inline;{$ENDIF}
var
LAvailable: TIdStreamSize;
begin
LAvailable := IndyMax(ABuffer.Size - ABuffer.Position, 0);
if ALength < 0 then begin
Result := LAvailable;
end else begin
Result := IndyMin(LAvailable, ALength);
end;
end;
const
wdays: array[1..7] of string = ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'); {do not localize}
monthnames: array[1..12] of string = ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', {do not localize}
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'); {do not localize}
{$IFDEF HAS_TFormatSettings}
//Delphi5 does not have TFormatSettings
//this should be changed to a singleton?
function GetEnglishSetting: TFormatSettings;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Result.CurrencyFormat := $00; // 0 = '$1'
Result.NegCurrFormat := $00; //0 = '($1)'
Result.CurrencyString := '$'; {do not localize}
Result.CurrencyDecimals := 2;
Result.ThousandSeparator := ','; {do not localize}
Result.DecimalSeparator := '.'; {do not localize}
Result.DateSeparator := '/'; {do not localize}
Result.ShortDateFormat := 'M/d/yyyy'; {do not localize}
Result.LongDateFormat := 'dddd, MMMM dd, yyyy'; {do not localize}
Result.TimeSeparator := ':'; {do not localize}
Result.TimeAMString := 'AM'; {do not localize}
Result.TimePMString := 'PM'; {do not localize}
Result.LongTimeFormat := 'h:mm:ss AMPM'; {do not localize}
Result.ShortTimeFormat := 'h:mm AMPM'; {do not localize}
Result.ShortMonthNames[1] := monthnames[1]; //'Jan';
Result.ShortMonthNames[2] := monthnames[2]; //'Feb';
Result.ShortMonthNames[3] := monthnames[3]; //'Mar';
Result.ShortMonthNames[4] := monthnames[4]; //'Apr';
Result.ShortMonthNames[5] := monthnames[5]; //'May';
Result.ShortMonthNames[6] := monthnames[6]; //'Jun';
Result.ShortMonthNames[7] := monthnames[7]; //'Jul';
Result.ShortMonthNames[8] := monthnames[8]; //'Aug';
Result.ShortMonthNames[9] := monthnames[9]; //'Sep';
Result.ShortMonthNames[10] := monthnames[10];// 'Oct';
Result.ShortMonthNames[11] := monthnames[11]; //'Nov';
Result.ShortMonthNames[12] := monthnames[12]; //'Dec';
Result.LongMonthNames[1] := 'January'; {do not localize}
Result.LongMonthNames[2] := 'February'; {do not localize}
Result.LongMonthNames[3] := 'March'; {do not localize}
Result.LongMonthNames[4] := 'April'; {do not localize}
Result.LongMonthNames[5] := 'May'; {do not localize}
Result.LongMonthNames[6] := 'June'; {do not localize}
Result.LongMonthNames[7] := 'July'; {do not localize}
Result.LongMonthNames[8] := 'August'; {do not localize}
Result.LongMonthNames[9] := 'September'; {do not localize}
Result.LongMonthNames[10] := 'October'; {do not localize}
Result.LongMonthNames[11] := 'November'; {do not localize}
Result.LongMonthNames[12] := 'December'; {do not localize}
Result.ShortDayNames[1] := wdays[1]; //'Sun';
Result.ShortDayNames[2] := wdays[2]; //'Mon';
Result.ShortDayNames[3] := wdays[3]; //'Tue';
Result.ShortDayNames[4] := wdays[4]; //'Wed';
Result.ShortDayNames[5] := wdays[5]; //'Thu';
Result.ShortDayNames[6] := wdays[6]; //'Fri';
Result.ShortDayNames[7] := wdays[7]; //'Sat';
Result.LongDayNames[1] := 'Sunday'; {do not localize}
Result.LongDayNames[2] := 'Monday'; {do not localize}
Result.LongDayNames[3] := 'Tuesday'; {do not localize}
Result.LongDayNames[4] := 'Wednesday'; {do not localize}
Result.LongDayNames[5] := 'Thursday'; {do not localize}
Result.LongDayNames[6] := 'Friday'; {do not localize}
Result.LongDayNames[7] := 'Saturday'; {do not localize}
Result.ListSeparator := ','; {do not localize}
end;
{$ENDIF}
// RLebeau 10/24/2008: In the RTM release of Delphi/C++Builder 2009, the
// overloaded version of SysUtils.Format() that has a TFormatSettings parameter
// has an internal bug that causes an EConvertError exception when UnicodeString
// parameters greater than 4094 characters are passed to it. Refer to QC #67934
// for details. The bug is fixed in 2009 Update 1. For RTM, call FormatBuf()
// directly to work around the problem...
function IndyFormat(const AFormat: string; const Args: array of const): string;
{$IFNDEF DOTNET}
{$IFDEF HAS_TFormatSettings}
var
EnglishFmt: TFormatSettings;
{$IFDEF BROKEN_FmtStr}
Len, BufLen: Integer;
Buffer: array[0..4095] of Char;
{$ENDIF}
{$ENDIF}
{$ENDIF}
begin
{$IFDEF DOTNET}
// RLebeau 10/29/09: temporary workaround until we figure out how to use
// SysUtils.FormatBuf() correctly under .NET in D2009 RTM...
Result := SysUtils.Format(AFormat, Args);
{$ELSE}
{$IFDEF HAS_TFormatSettings}
EnglishFmt := GetEnglishSetting;
{$IFDEF BROKEN_FmtStr}
BufLen := Length(Buffer);
if Length(AFormat) < (Length(Buffer) - (Length(Buffer) div 4)) then
begin
Len := SysUtils.FormatBuf(Buffer, Length(Buffer) - 1, Pointer(AFormat)^,
Length(AFormat), Args, EnglishFmt);
end else
begin
BufLen := Length(AFormat);
Len := BufLen;
end;
if Len >= BufLen - 1 then
begin
while Len >= BufLen - 1 do
begin
Inc(BufLen, BufLen);
Result := ''; // prevent copying of existing data, for speed
SetLength(Result, BufLen);
Len := SysUtils.FormatBuf(PChar(Result), BufLen - 1, Pointer(AFormat)^,
Length(AFormat), Args, EnglishFmt);
end;
SetLength(Result, Len);
end else
begin
SetString(Result, Buffer, Len);
end;
{$ELSE}
Result := SysUtils.Format(AFormat, Args, EnglishFmt);
{$ENDIF}
{$ELSE}
//Is there a way to get delphi5 to use locale in format? something like:
// SetThreadLocale(TheNewLocaleId);
// GetFormatSettings;
// Application.UpdateFormatSettings := False; //needed?
// format()
// set locale back to prior
Result := SysUtils.Format(AFormat, Args);
{$ENDIF}
{$ENDIF}
end;
function DateTimeGMTToHttpStr(const GMTValue: TDateTime) : String;
// should adhere to RFC 2616
var
wDay, wMonth, wYear: Word;
begin
DecodeDate(GMTValue, wYear, wMonth, wDay);
Result := IndyFormat('%s, %.2d %s %.4d %s %s', {do not localize}
[wdays[DayOfWeek(GMTValue)], wDay, monthnames[wMonth],
wYear, FormatDateTime('HH":"nn":"ss',GMTValue), 'GMT']); {do not localize}
end;
function DateTimeGMTToCookieStr(const GMTValue: TDateTime; const AUseNetscapeFmt: Boolean = True) : String;
var
wDay, wMonth, wYear: Word;
LDelim: Char;
begin
DecodeDate(GMTValue, wYear, wMonth, wDay);
// RLebeau: cookie draft-23 requires HTTP servers to format an Expires value as follows:
//
// Wdy, DD Mon YYYY HH:MM:SS GMT
//
// However, Netscape style formatting, which RFCs 2109 and 2965 allow
// (but draft-23 obsoletes), are more common:
//
// Wdy, DD-Mon-YY HH:MM:SS GMT (original)
// Wdy, DD-Mon-YYYY HH:MM:SS GMT (RFC 1123)
//
if AUseNetscapeFmt then begin
LDelim := '-'; {do not localize}
end else begin
LDelim := ' '; {do not localize}
end;
Result := IndyFormat('%s, %.2d%s%s%s%.4d %s %s', {do not localize}
[wdays[DayOfWeek(GMTValue)], wDay, LDelim, monthnames[wMonth], LDelim, wYear,
FormatDateTime('HH":"nn":"ss',GMTValue), 'GMT']); {do not localize}
end;
function DateTimeGMTToImapStr(const GMTValue: TDateTime) : String;
var
wDay, wMonth, wYear: Word;
LDay: String;
begin
DecodeDate(GMTValue, wYear, wMonth, wDay);
LDay := IntToStr(wDay);
if Length(LDay) < 2 then begin
LDay := ' ' + LDay; // NOTE: space NOT zero!
end;
Result := IndyFormat('%s-%s-%d %s %s', {do not localize}
[LDay, monthnames[wMonth], wYear, FormatDateTime('HH":"nn":"ss',GMTValue), {do not localize}
'+0000']); {do not localize}
end;
function LocalDateTimeToHttpStr(const Value: TDateTime) : String;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Result := DateTimeGMTToHttpStr(Value - OffsetFromUTC);
end;
function LocalDateTimeToCookieStr(const Value: TDateTime; const AUseNetscapeFmt: Boolean = True) : String;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Result := DateTimeGMTToCookieStr(Value - OffsetFromUTC, AUseNetscapeFmt);
end;
function LocalDateTimeToImapStr(const Value: TDateTime) : String;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Result := DateTimeGMTToImapStr(Value - OffsetFromUTC);
end;
{$I IdDeprecatedImplBugOff.inc}
function DateTimeToInternetStr(const Value: TDateTime; const AUseGMTStr : Boolean = False) : String;
{$I IdDeprecatedImplBugOn.inc}
begin
Result := LocalDateTimeToGMT(Value, AUseGMTStr);
end;
{This should never be localized}
function LocalDateTimeToGMT(const Value: TDateTime; const AUseGMTStr: Boolean = False) : String;
var
wDay, wMonth, wYear: Word;
begin
DecodeDate(Value, wYear, wMonth, wDay);
Result := IndyFormat('%s, %d %s %d %s %s', {do not localize}
[wdays[DayOfWeek(Value)], wDay, monthnames[wMonth],
wYear, FormatDateTime('HH":"nn":"ss', Value), {do not localize}
UTCOffsetToStr(OffsetFromUTC, AUseGMTStr)]);
end;
{$I IdDeprecatedImplBugOff.inc}
function DateTimeToGmtOffSetStr(ADateTime: TDateTime; const AUseGMTStr: Boolean = False): string;
{$I IdDeprecatedImplBugOn.inc}
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Result := UTCOffsetToStr(ADateTime, AUseGMTStr);
end;
function OffsetFromUTC: TDateTime;
{$IFDEF DOTNET}
{$IFDEF USE_INLINE}inline;{$ENDIF}
{$ELSE}
{$IFDEF WINDOWS}
var
iBias: Integer;
tmez: TTimeZoneInformation;
{$ENDIF}
{$IFDEF UNIX}
{$IFDEF USE_VCL_POSIX}
var
T : Time_t;
TV : TimeVal;
UT : tm;
{$ENDIF}
{$IFDEF USE_BASEUNIX}
var
timeval: TTimeVal;
timezone: TTimeZone;
{$ENDIF}
{$IFDEF KYLIXCOMPAT}
var
T: Time_T;
TV: TTimeVal;
UT: TUnixTime;
{$ENDIF}
{$ENDIF}
{$ENDIF}
begin
{$IFDEF UNIX}
{$IFDEF USE_VCL_POSIX}
{from http://edn.embarcadero.com/article/27890 but without multiplying the Result by -1}
gettimeofday(TV, nil);
T := TV.tv_sec;
localtime_r(T, UT);
Result := UT.tm_gmtoff / 60 / 60 / 24;
{$ENDIF}
{$IFDEF USE_BASEUNIX}
fpGetTimeOfDay (@TimeVal, @TimeZone);
Result := -1 * (timezone.tz_minuteswest / 60 / 24)
{$ENDIF}
{$IFDEF KYLIXCOMPAT}
{from http://edn.embarcadero.com/article/27890 but without multiplying the Result by -1}
gettimeofday(TV, nil);
T := TV.tv_sec;
localtime_r(@T, UT);
Result := UT.__tm_gmtoff / 60 / 60 / 24;
{$ENDIF}
{$ENDIF}
{$IFDEF DOTNET}
Result := System.Timezone.CurrentTimezone.GetUTCOffset(DateTime.FromOADate(Now)).TotalDays;
{$ENDIF}
{$IFDEF WINDOWS}
case GetTimeZoneInformation({$IFDEF WINCE}@{$ENDIF}tmez) of
TIME_ZONE_ID_INVALID :
raise EIdFailedToRetreiveTimeZoneInfo.Create(RSFailedTimeZoneInfo);
TIME_ZONE_ID_UNKNOWN :
iBias := tmez.Bias;
TIME_ZONE_ID_DAYLIGHT : begin
iBias := tmez.Bias;
if tmez.DaylightDate.wMonth <> 0 then begin
iBias := iBias + tmez.DaylightBias;
end;
end;
TIME_ZONE_ID_STANDARD : begin
iBias := tmez.Bias;
if tmez.StandardDate.wMonth <> 0 then begin
iBias := iBias + tmez.StandardBias;
end;
end
else
begin
raise EIdFailedToRetreiveTimeZoneInfo.Create(RSFailedTimeZoneInfo);
end;
end;
{We use ABS because EncodeTime will only accept positive values}
Result := EncodeTime(Abs(iBias) div 60, Abs(iBias) mod 60, 0, 0);
{The GetTimeZone function returns values oriented towards converting
a GMT time into a local time. We wish to do the opposite by returning
the difference between the local time and GMT. So I just make a positive
value negative and leave a negative value as positive}
if iBias > 0 then begin
Result := 0.0 - Result;
end;
{$ENDIF}
end;
function UTCOffsetToStr(const AOffset: TDateTime; const AUseGMTStr: Boolean = False): string;
var
AHour, AMin, ASec, AMSec: Word;
{$IFDEF STRING_IS_IMMUTABLE}
LSB: TIdStringBuilder;
{$ENDIF}
begin
if (AOffset = 0.0) and AUseGMTStr then
begin
Result := 'GMT'; {do not localize}
end else
begin
DecodeTime(AOffset, AHour, AMin, ASec, AMSec);
{$IFDEF STRING_IS_IMMUTABLE}
LSB := TIdStringBuilder.Create(5);
LSB.Append(IndyFormat(' %0.2d%0.2d', [AHour, AMin])); {do not localize}
if AOffset < 0.0 then begin
LSB[0] := '-'; {do not localize}
end else begin
LSB[0] := '+'; {do not localize}
end;
Result := LSB.ToString;
{$ELSE}
Result := IndyFormat(' %0.2d%0.2d', [AHour, AMin]); {do not localize}
if AOffset < 0.0 then begin
Result[1] := '-'; {do not localize}
end else begin
Result[1] := '+'; {do not localize}
end;
{$ENDIF}
end;
end;
function IndyIncludeTrailingPathDelimiter(const S: string): string;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
{$IFDEF HAS_SysUtils_IncludeExcludeTrailingPathDelimiter}
Result := SysUtils.IncludeTrailingPathDelimiter(S);
{$ELSE}
Result := SysUtils.IncludeTrailingBackslash(S);
{$ENDIF}
end;
function IndyExcludeTrailingPathDelimiter(const S: string): string;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
{$IFDEF HAS_SysUtils_IncludeExcludeTrailingPathDelimiter}
Result := SysUtils.ExcludeTrailingPathDelimiter(S);
{$ELSE}
Result := SysUtils.ExcludeTrailingBackslash(S);
{$ENDIF}
end;
function StringsReplace(const S: String; const OldPattern, NewPattern: array of string): string;
var
i : Integer;
begin
// TODO: re-write this to not use ReplaceAll() in a loop anymore. If
// OldPattern contains multiple strings, a string appearing later in the
// list may be replaced multiple times by accident if it appears in the
// Result of an earlier string replacement.
Result := s;
for i := Low(OldPattern) to High(OldPattern) do begin
Result := ReplaceAll(Result, OldPattern[i], NewPattern[i]);
end;
end;
{$IFNDEF DOTNET}
{$IFNDEF HAS_PosEx}
function PosEx(const SubStr, S: string; Offset: Integer): Integer;
var
I, LIterCnt, L, J: Integer;
PSubStr, PS: PChar;
begin
Result := 0;
if SubStr = '' then begin
Exit;
end;
{ Calculate the number of possible iterations. Not valid if Offset < 1. }
LIterCnt := Length(S) - Offset - Length(SubStr) + 1;
{ Only continue if the number of iterations is positive or zero (there is space to check) }
if (Offset > 0) and (LIterCnt >= 0) then
begin
L := Length(SubStr);
PSubStr := PChar(SubStr);
PS := PChar(S);
Inc(PS, Offset - 1);
for I := 0 to LIterCnt do
begin
J := 0;
while (J >= 0) and (J < L) do
begin
if PS[I + J] = PSubStr[J] then begin
Inc(J);
end else begin
J := -1;
end;
end;
if J >= L then begin
Result := I + Offset;
Exit;
end;
end;
end;
end;
{$ENDIF}
{$ENDIF}
function ReplaceAll(const S: String; const OldPattern, NewPattern: String): String;
var
I, PatLen: Integer;
{$IFDEF DOTNET}
J: Integer;
{$ELSE}
NumBytes: Integer;
{$ENDIF}
begin
PatLen := Length(OldPattern);
if Length(NewPattern) = PatLen then begin
Result := S;
I := Pos(OldPattern, Result);
if I > 0 then begin
UniqueString(Result);
{$IFNDEF DOTNET}
NumBytes := PatLen * SizeOf(Char);
{$ENDIF}
repeat
{$IFDEF DOTNET}
for J := 1 to PatLen do begin
Result[I+J-1] := NewPattern[J];
end;
{$ELSE}
Move(PChar(NewPattern)^, Result[I], NumBytes);
{$ENDIF}
I := PosEx(OldPattern, Result, I + PatLen);
until I = 0;
end;
end else begin
Result := SysUtils.StringReplace(S, OldPattern, NewPattern, [rfReplaceAll]);
end;
end;
function ReplaceOnlyFirst(const S, OldPattern, NewPattern: string): string;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Result := SysUtils.StringReplace(s, OldPattern, NewPattern, []);
end;
function IndyStrToInt(const S: string): Integer;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Result := StrToInt(Trim(S));
end;
function IndyStrToInt(const S: string; ADefault: Integer): Integer;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Result := StrToIntDef(Trim(S), ADefault);
end;
function CompareDate(const D1, D2: TDateTime): Integer;
var
LTM1, LTM2 : TTimeStamp;
begin
LTM1 := DateTimeToTimeStamp(D1);
LTM2 := DateTimeToTimeStamp(D2);
if LTM1.Date = LTM2.Date then begin
if LTM1.Time < LTM2.Time then begin
Result := -1;
end
else if LTM1.Time > LTM2.Time then begin
Result := 1;
end
else begin
Result := 0;
end;
end
else if LTM1.Date > LTM2.Date then begin
Result := 1;
end
else begin
Result := -1;
end;
end;
function AddMSecToTime(const ADateTime: TDateTime; const AMSec: Integer): TDateTime;
{$IFDEF HAS_UNIT_DateUtils}
{$IFDEF USE_INLINE}inline;{$ENDIF}
{$ELSE}
var
LTM : TTimeStamp;
{$ENDIF}
begin
{$IFDEF HAS_UNIT_DateUtils}
Result := DateUtils.IncMilliSecond(ADateTime, AMSec);
{$ELSE}
LTM := DateTimeToTimeStamp(ADateTime);
LTM.Time := LTM.Time + AMSec;
Result := TimeStampToDateTime(LTM);
{$ENDIF}
end;
function IndyFileAge(const AFileName: string): TDateTime;
{$IFDEF HAS_2PARAM_FileAge}
{$IFDEF USE_INLINE}inline;{$ENDIF}
{$ELSE}
var
LAge: Integer;
{$ENDIF}
begin
{$IFDEF HAS_2PARAM_FileAge}
//single-parameter fileage is deprecated in d2006 and above
if not FileAge(AFileName, Result) then begin
Result := 0;
end;
{$ELSE}
LAge := SysUtils.FileAge(AFileName);
if LAge <> -1 then begin
Result := FileDateToDateTime(LAge);
end else begin
Result := 0.0;
end;
{$ENDIF}
end;
function IndyDirectoryExists(const ADirectory: string): Boolean;
{$IFDEF HAS_SysUtils_DirectoryExists}
{$IFDEF USE_INLINE}inline;{$ENDIF}
{$ELSE}
var
Code: Integer;
{$IFDEF STRING_UNICODE_MISMATCH}
LStr: TIdPlatformString;
{$ENDIF}
{$ENDIF}
begin
{$IFDEF HAS_SysUtils_DirectoryExists}
Result := SysUtils.DirectoryExists(ADirectory);
{$ELSE}
// RLebeau 2/16/2006: Removed dependency on the FileCtrl unit
{$IFDEF STRING_UNICODE_MISMATCH}
:= TIdPlatformString(ADirectory); // explicit convert to Ansi/Unicode
Code := GetFileAttributes(PIdPlatformChar(LStr));
{$ELSE}
Code := GetFileAttributes(PChar(ADirectory));
{$ENDIF}
Result := (Code <> -1) and ((Code and FILE_ATTRIBUTE_DIRECTORY) <> 0);
{$ENDIF}
end;
function IndyStrToInt64(const S: string; const ADefault: Int64): Int64;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Result := SysUtils.StrToInt64Def(Trim(S), ADefault);
end;
function IndyStrToInt64(const S: string): Int64;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Result := SysUtils.StrToInt64(Trim(S));
end;
function IndyStrToStreamSize(const S: string; const ADefault: TIdStreamSize): TIdStreamSize;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
{$IFDEF STREAM_SIZE_64}
Result := IndyStrToInt64(S, ADefault);
{$ELSE}
Result := IndyStrToInt(S, ADefault);
{$ENDIF}
end;
function IndyStrToStreamSize(const S: string): TIdStreamSize;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
{$IFDEF STREAM_SIZE_64}
Result := IndyStrToInt64(S);
{$ELSE}
Result := IndyStrToInt(S);
{$ENDIF}
end;
function ToBytes(const AValue: string; ADestEncoding: IIdTextEncoding = nil
{$IFDEF STRING_IS_ANSI}; ASrcEncoding: IIdTextEncoding = nil{$ENDIF}
): TIdBytes; overload;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Result := ToBytes(AValue, -1, 1, ADestEncoding
{$IFDEF STRING_IS_ANSI}, ASrcEncoding{$ENDIF}
);
end;
function ToBytes(const AValue: string; const ALength: Integer; const AIndex: Integer = 1;
ADestEncoding: IIdTextEncoding = nil
{$IFDEF STRING_IS_ANSI}; ASrcEncoding: IIdTextEncoding = nil{$ENDIF}
): TIdBytes; overload;
var
LLength: Integer;
{$IFDEF STRING_IS_ANSI}
LBytes: TIdBytes;
{$ENDIF}
begin
{$IFDEF STRING_IS_ANSI}
LBytes := nil; // keep the compiler happy
{$ENDIF}
LLength := IndyLength(AValue, ALength, AIndex);
if LLength > 0 then
begin
EnsureEncoding(ADestEncoding);
{$IFDEF STRING_IS_UNICODE}
SetLength(Result, ADestEncoding.GetByteCount(AValue, AIndex, LLength));
if Length(Result) > 0 then begin
ADestEncoding.GetBytes(AValue, AIndex, LLength, Result, 0);
end;
{$ELSE}
EnsureEncoding(ASrcEncoding, encOSDefault);
LBytes := RawToBytes(AValue[AIndex], LLength);
CheckByteEncoding(LBytes, ASrcEncoding, ADestEncoding);
Result := LBytes;
{$ENDIF}
end else begin
SetLength(Result, 0);
end;
end;
function ToBytes(const AValue: Char; ADestEncoding: IIdTextEncoding = nil
{$IFDEF STRING_IS_ANSI}; ASrcEncoding: IIdTextEncoding = nil{$ENDIF}
): TIdBytes; overload;
var
{$IFDEF STRING_IS_UNICODE}
LChars: {$IFDEF DOTNET}array[0..0] of Char{$ELSE}TIdWideChars{$ENDIF};
{$ELSE}
LBytes: TIdBytes;
{$ENDIF}
begin
EnsureEncoding(ADestEncoding);
{$IFDEF STRING_IS_UNICODE}
{$IFNDEF DOTNET}
SetLength(LChars, 1);
{$ENDIF}
LChars[0] := AValue;
Result := ADestEncoding.GetBytes(LChars);
{$ELSE}
EnsureEncoding(ASrcEncoding, encOSDefault);
LBytes := RawToBytes(AValue, 1);
CheckByteEncoding(LBytes, ASrcEncoding, ADestEncoding);
Result := LBytes;
{$ENDIF}
end;
function ToBytes(const AValue: Int64): TIdBytes; overload;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
{$IFDEF DOTNET}
Result := System.BitConverter.GetBytes(AValue);
{$ELSE}
SetLength(Result, SizeOf(Int64));
PInt64(@Result[0])^ := AValue;
{$ENDIF}
end;
function ToBytes(const AValue: TIdUInt64): TIdBytes; overload;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
{$IFDEF DOTNET}
Result := System.BitConverter.GetBytes(AValue);
{$ELSE}
SetLength(Result, SizeOf(UInt64));
PUInt64(@Result[0])^ := AValue{$IFDEF TIdUInt64_IS_NOT_NATIVE}.QuadPart{$ENDIF};
{$ENDIF}
end;
function ToBytes(const AValue: Int32): TIdBytes; overload;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
{$IFDEF DOTNET}
Result := System.BitConverter.GetBytes(AValue);
{$ELSE}
SetLength(Result, SizeOf(Int32));
PInt32(@Result[0])^ := AValue;
{$ENDIF}
end;
function ToBytes(const AValue: UInt32): TIdBytes; overload;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
{$IFDEF DOTNET}
Result := System.BitConverter.GetBytes(AValue);
{$ELSE}
SetLength(Result, SizeOf(UInt32));
PUInt32(@Result[0])^ := AValue;
{$ENDIF}
end;
function ToBytes(const AValue: Int16): TIdBytes; overload;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
{$IFDEF DOTNET}
Result := System.BitConverter.GetBytes(AValue);
{$ELSE}
SetLength(Result, SizeOf(Int16));
PInt16(@Result[0])^ := AValue;
{$ENDIF}
end;
function ToBytes(const AValue: UInt16): TIdBytes; overload;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
{$IFDEF DOTNET}
Result := System.BitConverter.GetBytes(AValue);
{$ELSE}
SetLength(Result, SizeOf(UInt16));
PUInt16(@Result[0])^ := AValue;
{$ENDIF}
end;
function ToBytes(const AValue: Int8): TIdBytes; overload;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
SetLength(Result, SizeOf(Int8));
Result[0] := Byte(AValue);
end;
function ToBytes(const AValue: UInt8): TIdBytes; overload;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
SetLength(Result, SizeOf(UInt8));
Result[0] := AValue;
end;
function ToBytes(const AValue: TIdBytes; const ASize: Integer; const AIndex: Integer = 0): TIdBytes; overload;
{$IFDEF USE_INLINE}inline;{$ENDIF}
var
LSize: Integer;
begin
LSize := IndyLength(AValue, ASize, AIndex);
SetLength(Result, LSize);
if LSize > 0 then begin
CopyTIdBytes(AValue, AIndex, Result, 0, LSize);
end;
end;
{$IFNDEF DOTNET}
function RawToBytes(const AValue; const ASize: Integer): TIdBytes;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
SetLength(Result, ASize);
if ASize > 0 then begin
Move(AValue, Result[0], ASize);
end;
end;
{$ENDIF}
procedure ToBytesF(var Bytes: TIdBytes; const AValue: Char; ADestEncoding: IIdTextEncoding = nil
{$IFDEF STRING_IS_ANSI}; ASrcEncoding: IIdTextEncoding = nil{$ENDIF}
);
{$IFDEF USE_INLINE}inline;{$ENDIF}
var
LChars: {$IFDEF DOTNET}array[0..0] of Char{$ELSE}TIdWideChars{$ENDIF};
begin
EnsureEncoding(ADestEncoding);
{$IFDEF STRING_IS_UNICODE}
{$IFNDEF DOTNET}
SetLength(LChars, 1);
{$ENDIF}
LChars[0] := AValue;
{$ELSE}
EnsureEncoding(ASrcEncoding, encOSDefault);
LChars := ASrcEncoding.GetChars(RawToBytes(AValue, 1)); // convert to Unicode
{$ENDIF}
Assert(Length(Bytes) >= ADestEncoding.GetByteCount(LChars));
ADestEncoding.GetBytes(LChars, 0, Length(LChars), Bytes, 0);
end;
procedure ToBytesF(var Bytes: TIdBytes; const AValue: Int32);
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Assert(Length(Bytes) >= SizeOf(AValue));
CopyTIdInt32(AValue, Bytes, 0);
end;
procedure ToBytesF(var Bytes: TIdBytes; const AValue: Int16);
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Assert(Length(Bytes) >= SizeOf(AValue));
CopyTIdInt16(AValue, Bytes, 0);
end;
procedure ToBytesF(var Bytes: TIdBytes; const AValue: UInt16);
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Assert(Length(Bytes) >= SizeOf(AValue));
CopyTIdUInt16(AValue, Bytes, 0);
end;
procedure ToBytesF(var Bytes: TIdBytes; const AValue: Int8);
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Assert(Length(Bytes) >= SizeOf(AValue));
Bytes[0] := Byte(AValue);
end;
procedure ToBytesF(var Bytes: TIdBytes; const AValue: UInt8);
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Assert(Length(Bytes) >= SizeOf(AValue));
Bytes[0] := AValue;
end;
procedure ToBytesF(var Bytes: TIdBytes; const AValue: UInt32);
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Assert(Length(Bytes) >= SizeOf(AValue));
CopyTIdUInt32(AValue, Bytes, 0);
end;
procedure ToBytesF(var Bytes: TIdBytes; const AValue: Int64);
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Assert(Length(Bytes) >= SizeOf(AValue));
CopyTIdInt64(AValue, Bytes, 0);
end;
procedure ToBytesF(var Bytes: TIdBytes; const AValue: TIdUInt64);
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Assert(Length(Bytes) >= SizeOf(AValue));
CopyTIdUInt64(AValue, Bytes, 0);
end;
procedure ToBytesF(var Bytes: TIdBytes; const AValue: TIdBytes; const ASize: Integer; const AIndex: Integer = 0);
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Assert(Length(Bytes) >= ASize);
CopyTIdBytes(AValue, AIndex, Bytes, 0, ASize);
end;
{$IFNDEF DOTNET}
procedure RawToBytesF(var Bytes: TIdBytes; const AValue; const ASize: Integer);
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Assert(Length(Bytes) >= ASize);
if ASize > 0 then begin
Move(AValue, Bytes[0], ASize);
end;
end;
{$ENDIF}
function BytesToChar(const AValue: TIdBytes; const AIndex: Integer = 0;
AByteEncoding: IIdTextEncoding = nil
{$IFDEF STRING_IS_ANSI}; ADestEncoding: IIdTextEncoding = nil{$ENDIF}
): Char; overload;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
BytesToChar(AValue, Result, AIndex, AByteEncoding{$IFDEF STRING_IS_ANSI}, ADestEncoding{$ENDIF});
end;
function BytesToChar(const AValue: TIdBytes; var VChar: Char; const AIndex: Integer = 0;
AByteEncoding: IIdTextEncoding = nil
{$IFDEF STRING_IS_ANSI}; ADestEncoding: IIdTextEncoding = nil{$ENDIF}
): Integer; overload;
var
I, J, NumChars, NumBytes: Integer;
{$IFDEF DOTNET}
LChars: array[0..1] of Char;
{$ELSE}
LChars: TIdWideChars;
{$IFDEF STRING_IS_ANSI}
LWTmp: WideString;
LATmp: TIdBytes;
{$ENDIF}
{$ENDIF}
begin
Result := 0;
EnsureEncoding(AByteEncoding);
// 2 Chars to handle UTF-16 surrogates
NumBytes := IndyMin(IndyLength(AValue, -1, AIndex), AByteEncoding.GetMaxByteCount(2));
{$IFNDEF DOTNET}
SetLength(LChars, 2);
{$ENDIF}
NumChars := 0;
if NumBytes > 0 then
begin
for I := 1 to NumBytes do
begin
NumChars := AByteEncoding.GetChars(AValue, AIndex, I, LChars, 0);
Inc(Result);
if NumChars > 0 then begin
// RLebeau 10/19/2012: when Indy switched to its own UTF-8 implementation
// to avoid the MB_ERR_INVALID_CHARS flag on Windows, it accidentally broke
// this loop! Since this is not commonly used, this was not noticed until
// now. On Windows at least, GetChars() now returns >0 for an invalid
// sequence, so we have to check if any of the returned characters are the
// Unicode U+FFFD character, indicating bad data...
for J := 0 to NumChars-1 do begin
if LChars[J] = TIdWideChar($FFFD) then begin
// keep reading...
NumChars := 0;
Break;
end;
end;
if NumChars > 0 then begin
Break;
end;
end;
end;
end;
{$IFDEF STRING_IS_UNICODE}
// RLebeau: if the bytes were decoded into surrogates, the second
// surrogate is lost here, as it can't be returned unless we cache
// it somewhere for the the next BytesToChar() call to retreive. Just
// raise an error for now. Users will have to update their code to
// read surrogates differently...
Assert(NumChars = 1);
VChar := LChars[0];
{$ELSE}
// RLebeau: since we can only return an AnsiChar here, let's convert
// the decoded characters, surrogates and all, into their Ansi
// representation. This will have the same problem as above if the
// conversion results in a multibyte character sequence...
EnsureEncoding(ADestEncoding, encOSDefault);
SetString(LWTmp, PWideChar(LChars), NumChars);
LATmp := ADestEncoding.GetBytes(LWTmp); // convert to Ansi
Assert(Length(LATmp) = 1);
VChar := Char(LATmp[0]);
{$ENDIF}
end;
function BytesToInt32(const AValue: TIdBytes; const AIndex: Integer = 0): Int32;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Assert(Length(AValue) >= (AIndex+SizeOf(Int32)));
{$IFDEF DOTNET}
Result := System.BitConverter.ToInt32(AValue, AIndex);
{$ELSE}
Result := PInt32(@AValue[AIndex])^;
{$ENDIF}
end;
{$I IdDeprecatedImplBugOff.inc}
function BytesToLongInt(const AValue: TIdBytes; const AIndex: Integer = 0): Integer;
{$I IdDeprecatedImplBugOff.inc}
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Result := BytesToInt32(AValue, AIndex);
end;
function BytesToInt64(const AValue: TIdBytes; const AIndex: Integer = 0): Int64;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Assert(Length(AValue) >= (AIndex+SizeOf(Int64)));
{$IFDEF DOTNET}
Result := System.BitConverter.ToInt64(AValue, AIndex);
{$ELSE}
Result := PInt64(@AValue[AIndex])^;
{$ENDIF}
end;
function BytesToUInt64(const AValue: TIdBytes; const AIndex: Integer = 0): TIdUInt64;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Assert(Length(AValue) >= (AIndex+SizeOf(TIdUInt64)));
{$IFDEF DOTNET}
Result := System.BitConverter.ToUInt64(AValue, AIndex);
{$ELSE}
Result{$IFDEF TIdUInt64_IS_NOT_NATIVE}.QuadPart{$ENDIF} := PUInt64(@AValue[AIndex])^;
{$ENDIF}
end;
function BytesToTicks(const AValue: TIdBytes; const AIndex: Integer = 0): TIdTicks;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
{$IFDEF UInt64_IS_NATIVE}
Result := BytesToUInt64(AValue, AIndex);
{$ELSE}
Result := BytesToInt64(AValue, AIndex);
{$ENDIF}
end;
function BytesToUInt16(const AValue: TIdBytes; const AIndex: Integer = 0): UInt16;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Assert(Length(AValue) >= (AIndex+SizeOf(UInt16)));
{$IFDEF DOTNET}
Result := System.BitConverter.ToUInt16(AValue, AIndex);
{$ELSE}
Result := PUInt16(@AValue[AIndex])^;
{$ENDIF}
end;
{$I IdDeprecatedImplBugOff.inc}
function BytesToWord(const AValue: TIdBytes; const AIndex: Integer = 0): UInt16;
{$I IdDeprecatedImplBugOn.inc}
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Result := BytesToUInt16(AValue, AIndex);
end;
function BytesToInt16(const AValue: TIdBytes; const AIndex: Integer = 0): Int16;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Assert(Length(AValue) >= (AIndex+SizeOf(Int16)));
{$IFDEF DOTNET}
Result := System.BitConverter.ToInt16(AValue, AIndex);
{$ELSE}
Result := PInt16(@AValue[AIndex])^;
{$ENDIF}
end;
{$I IdDeprecatedImplBugOff.inc}
function BytesToShort(const AValue: TIdBytes; const AIndex: Integer = 0): Int16;
{$I IdDeprecatedImplBugOn.inc}
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Result := BytesToInt16(AValue, AIndex);
end;
function BytesToIPv4Str(const AValue: TIdBytes; const AIndex: Integer = 0): String;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Assert(Length(AValue) >= (AIndex+4));
Result := IntToStr(Ord(AValue[AIndex])) + '.' +
IntToStr(Ord(AValue[AIndex+1])) + '.' +
IntToStr(Ord(AValue[AIndex+2])) + '.' +
IntToStr(Ord(AValue[AIndex+3]));
end;
procedure BytesToIPv6(const AValue: TIdBytes; var VAddress: TIdIPv6Address; const AIndex: Integer = 0);
{$IFDEF DOTNET}
var
I: Integer;
{$ELSE}
{$IFDEF USE_INLINE}inline;{$ENDIF}
{$ENDIF}
begin
Assert(Length(AValue) >= (AIndex+16));
{$IFDEF DOTNET}
for i := 0 to 7 do begin
VAddress[i] := TwoByteToUInt16(AValue[(i*2)+AIndex], AValue[(i*2)+1+AIndex]);
end;
{$ELSE}
Move(AValue[AIndex], VAddress[0], 16);
{$ENDIF}
end;
function BytesToUInt32(const AValue: TIdBytes; const AIndex: Integer = 0): UInt32;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Assert(Length(AValue) >= (AIndex+SizeOf(UInt32)));
{$IFDEF DOTNET}
Result := System.BitConverter.ToUInt32(AValue, AIndex);
{$ELSE}
Result := PUInt32(@AValue[AIndex])^;
{$ENDIF}
end;
{$I IdDeprecatedImplBugOff.inc}
function BytesToLongWord(const AValue: TIdBytes; const AIndex: Integer = 0): UInt32;
{$I IdDeprecatedImplBugOn.inc}
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Result := BytesToUInt32(AValue, AIndex);
end;
function BytesToString(const AValue: TIdBytes; AByteEncoding: IIdTextEncoding = nil
{$IFDEF STRING_IS_ANSI}; ADestEncoding: IIdTextEncoding = nil{$ENDIF}
): string; overload;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Result := BytesToString(AValue, 0, -1, AByteEncoding
{$IFDEF STRING_IS_ANSI}, ADestEncoding{$ENDIF}
);
end;
function BytesToString(const AValue: TIdBytes; const AStartIndex: Integer;
const ALength: Integer = -1; AByteEncoding: IIdTextEncoding = nil
{$IFDEF STRING_IS_ANSI}; ADestEncoding: IIdTextEncoding = nil{$ENDIF}
): string; overload;
var
LLength: Integer;
{$IFDEF STRING_IS_ANSI}
LBytes: TIdBytes;
{$ENDIF}
begin
{$IFDEF STRING_IS_ANSI}
LBytes := nil; // keep the compiler happy
{$ENDIF}
LLength := IndyLength(AValue, ALength, AStartIndex);
if LLength > 0 then begin
EnsureEncoding(AByteEncoding);
{$IFDEF STRING_IS_UNICODE}
Result := AByteEncoding.GetString(AValue, AStartIndex, LLength);
{$ELSE}
EnsureEncoding(ADestEncoding);
if (AStartIndex = 0) and (LLength = Length(AValue)) then begin
LBytes := AValue;
end else begin
LBytes := Copy(AValue, AStartIndex, LLength);
end;
CheckByteEncoding(LBytes, AByteEncoding, ADestEncoding);
SetString(Result, PAnsiChar(LBytes), Length(LBytes));
{$ENDIF}
end else begin
Result := '';
end;
end;
function BytesToStringRaw(const AValue: TIdBytes): string; overload;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Result := BytesToStringRaw(AValue, 0, -1);
end;
function BytesToStringRaw(const AValue: TIdBytes; const AStartIndex: Integer;
const ALength: Integer = -1): string;
var
LLength: Integer;
begin
LLength := IndyLength(AValue, ALength, AStartIndex);
if LLength > 0 then begin
{$IFDEF STRING_IS_UNICODE}
Result := IndyTextEncoding_8Bit.GetString(AValue, AStartIndex, LLength);
{$ELSE}
SetString(Result, PAnsiChar(@AValue[AStartIndex]), LLength);
{$ENDIF}
end else begin
Result := '';
end;
end;
{$IFNDEF DOTNET}
procedure BytesToRaw(const AValue: TIdBytes; var VBuffer; const ASize: Integer);
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Assert(Length(AValue) >= ASize);
Move(AValue[0], VBuffer, ASize);
end;
{$ENDIF}
function TwoByteToUInt16(AByte1, AByte2: Byte): UInt16;
//Since Replys are returned as Strings, we need a routine to convert two
// characters which are a 2 byte U Int into a two byte unsigned Integer
var
LWord: TIdBytes;
begin
SetLength(LWord, SizeOf(UInt16));
LWord[0] := AByte1;
LWord[1] := AByte2;
Result := BytesToUInt16(LWord);
// Result := UInt16((AByte1 shl 8) and $FF00) or UInt16(AByte2 and $00FF);
end;
{$I IdDeprecatedImplBugOff.inc}
function TwoByteToWord(AByte1, AByte2: Byte): UInt16;
{$I IdDeprecatedImplBugOn.inc}
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Result := TwoByteToUInt16(AByte1, AByte2);
end;
function ReadStringFromStream(AStream: TStream; ASize: Integer = -1;
AByteEncoding: IIdTextEncoding = nil
{$IFDEF STRING_IS_ANSI}; ADestEncoding: IIdTextEncoding = nil{$ENDIF}
): string;
var
LBytes: TIdBytes;
begin
ASize := TIdStreamHelper.ReadBytes(AStream, LBytes, ASize);
Result := BytesToString(LBytes, 0, ASize, AByteEncoding
{$IFDEF STRING_IS_ANSI}, ADestEncoding{$ENDIF}
);
end;
function ReadTIdBytesFromStream(const AStream: TStream; var ABytes: TIdBytes;
const Count: TIdStreamSize; const AIndex: Integer = 0): TIdStreamSize;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Result := TIdStreamHelper.ReadBytes(AStream, ABytes, Count, AIndex);
end;
function ReadCharFromStream(AStream: TStream; var VChar: Char;
AByteEncoding: IIdTextEncoding = nil
{$IFDEF STRING_IS_ANSI}; ADestEncoding: IIdTextEncoding = nil{$ENDIF}
): Integer;
var
StartPos: TIdStreamSize;
Lb: Byte;
I, NumChars, NumBytes: Integer;
LBytes: TIdBytes;
{$IFDEF DOTNET}
LChars: array[0..1] of Char;
{$ELSE}
LChars: TIdWideChars;
{$IFDEF STRING_IS_ANSI}
LWTmp: WideString;
LATmp: TIdBytes;
{$ENDIF}
{$ENDIF}
function ReadByte: Byte;
begin
if AStream.Read(Result{$IFNDEF DOTNET}, 1{$ENDIF}) <> 1 then begin
raise EIdException.Create('Unable to read byte'); {do not localize}
end;
end;
begin
Result := 0;
{$IFDEF STRING_IS_ANSI}
LATmp := nil; // keep the compiler happy
{$ENDIF}
EnsureEncoding(AByteEncoding);
StartPos := AStream.Position;
// don't raise an exception here, backwards compatibility for now
if AStream.Read(Lb{$IFNDEF DOTNET}, 1{$ENDIF}) <> 1 then begin
Exit;
end;
Result := 1;
// 2 Chars to handle UTF-16 surrogates
NumBytes := AByteEncoding.GetMaxByteCount(2);
SetLength(LBytes, NumBytes);
{$IFNDEF DOTNET}
SetLength(LChars, 2);
{$ENDIF}
try
repeat
LBytes[Result-1] := Lb;
NumChars := AByteEncoding.GetChars(LBytes, 0, Result, LChars, 0);
if NumChars > 0 then begin
// RLebeau 10/19/2012: when Indy switched to its own UTF-8 implementation
// to avoid the MB_ERR_INVALID_CHARS flag on Windows, it accidentally broke
// this loop! Since this is not commonly used, this was not noticed until
// now. On Windows at least, GetChars() now returns >0 for an invalid
// sequence, so we have to check if any of the returned characters are the
// Unicode U+FFFD character, indicating bad data...
for I := 0 to NumChars-1 do begin
if LChars[I] = TIdWideChar($FFFD) then begin
// keep reading...
NumChars := 0;
Break;
end;
end;
if NumChars > 0 then begin
Break;
end;
end;
if Result = NumBytes then begin
Break;
end;
Lb := ReadByte;
Inc(Result);
until False;
except
AStream.Position := StartPos;
raise;
end;
{$IFDEF STRING_IS_UNICODE}
// RLebeau: if the bytes were decoded into surrogates, the second
// surrogate is lost here, as it can't be returned unless we cache
// it somewhere for the the next ReadTIdBytesFromStream() call to
// retreive. Just raise an error for now. Users will have to
// update their code to read surrogates differently...
Assert(NumChars = 1);
VChar := LChars[0];
{$ELSE}
// RLebeau: since we can only return an AnsiChar here, let's convert
// the decoded characters, surrogates and all, into their Ansi
// representation. This will have the same problem as above if the
// conversion results in a multibyte character sequence...
EnsureEncoding(ADestEncoding, encOSDefault);
SetString(LWTmp, PWideChar(LChars), NumChars);
LATmp := ADestEncoding.GetBytes(LWTmp); // convert to Ansi
Assert(Length(LATmp) = 1);
VChar := Char(LATmp[0]);
{$ENDIF}
end;
procedure WriteTIdBytesToStream(const AStream: TStream; const ABytes: TIdBytes;
const ASize: Integer = -1; const AIndex: Integer = 0);
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
TIdStreamHelper.Write(AStream, ABytes, ASize, AIndex);
end;
procedure WriteStringToStream(AStream: TStream; const AStr: string;
ADestEncoding: IIdTextEncoding
{$IFDEF STRING_IS_ANSI}; ASrcEncoding: IIdTextEncoding = nil{$ENDIF}
);
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
WriteStringToStream(AStream, AStr, -1, 1, ADestEncoding
{$IFDEF STRING_IS_ANSI}, ASrcEncoding{$ENDIF}
);
end;
procedure WriteStringToStream(AStream: TStream; const AStr: string;
const ALength: Integer = -1; const AIndex: Integer = 1;
ADestEncoding: IIdTextEncoding = nil
{$IFDEF STRING_IS_ANSI}; ASrcEncoding: IIdTextEncoding = nil{$ENDIF}
);
{$IFDEF USE_INLINE}inline;{$ENDIF}
var
LLength: Integer;
LBytes: TIdBytes;
begin
LBytes := nil;
LLength := IndyLength(AStr, ALength, AIndex);
if LLength > 0 then
begin
LBytes := ToBytes(AStr, LLength, AIndex, ADestEncoding
{$IFDEF STRING_IS_ANSI}, ASrcEncoding{$ENDIF}
);
TIdStreamHelper.Write(AStream, LBytes);
end;
end;
{$IFDEF DOTNET}
function TIdBaseStream.Read(var VBuffer: array of Byte; AOffset, ACount: Longint): Longint;
var
LBytes: TIdBytes;
begin
// this is a silly work around really, but array of Byte and TIdByte aren't
// interchangable in a var parameter, though really they *should be*
SetLength(LBytes, ACount - AOffset);
Result := IdRead(LBytes, 0, ACount - AOffset);
CopyTIdByteArray(LBytes, 0, VBuffer, AOffset, Result);
end;
function TIdBaseStream.Write(const ABuffer: array of Byte; AOffset, ACount: Longint): Longint;
begin
Result := IdWrite(ABuffer, AOffset, ACount);
end;
function TIdBaseStream.Seek(const AOffset: Int64; AOrigin: TSeekOrigin): Int64;
begin
Result := IdSeek(AOffset, AOrigin);
end;
procedure TIdBaseStream.SetSize(ASize: Int64);
begin
IdSetSize(ASize);
end;
{$ELSE}
{$IFDEF STREAM_SIZE_64}
procedure TIdBaseStream.SetSize(const NewSize: Int64);
begin
IdSetSize(NewSize);
end;
{$ELSE}
procedure TIdBaseStream.SetSize(ASize: Integer);
begin
IdSetSize(ASize);
end;
{$ENDIF}
function TIdBaseStream.Read(var Buffer; Count: Longint): Longint;
var
LBytes: TIdBytes;
begin
SetLength(LBytes, Count);
Result := IdRead(LBytes, 0, Count);
if Result > 0 then begin
Move(LBytes[0], Buffer, Result);
end;
end;
function TIdBaseStream.Write(const Buffer; Count: Longint): Longint;
begin
if Count > 0 then begin
Result := IdWrite(RawToBytes(Buffer, Count), 0, Count);
end else begin
Result := 0;
end;
end;
{$IFDEF STREAM_SIZE_64}
function TIdBaseStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64;
begin
Result := IdSeek(Offset, Origin);
end;
{$ELSE}
function TIdBaseStream.Seek(Offset: Longint; Origin: Word): Longint;
var
LSeek : TSeekOrigin;
begin
case Origin of
soFromBeginning : LSeek := soBeginning;
soFromCurrent : LSeek := soCurrent;
soFromEnd : LSeek := soEnd;
else
Result := 0;
Exit;
end;
Result := IdSeek(Offset, LSeek) and $FFFFFFFF;
end;
{$ENDIF}
{$ENDIF}
function TIdCalculateSizeStream.IdRead(var VBuffer: TIdBytes; AOffset, ACount: Longint): Longint;
begin
Result := 0;
end;
function TIdCalculateSizeStream.IdWrite(const ABuffer: TIdBytes; AOffset, ACount: Longint): Longint;
var
I: Integer;
begin
I := IndyLength(ABuffer, ACount, AOffset);
if I > 0 then begin
Inc(FPosition, I);
if FPosition > FSize then begin
FSize := FPosition;
end;
end;
Result := I;
end;
function TIdCalculateSizeStream.IdSeek(const AOffset: Int64; AOrigin: TSeekOrigin): Int64;
begin
case AOrigin of
soBeginning: begin
FPosition := AOffset;
end;
soCurrent: begin
FPosition := FPosition + AOffset;
end;
soEnd: begin
FPosition := FSize + AOffset;
end;
end;
if FPosition < 0 then begin
FPosition := 0;
end;
Result := FPosition;
end;
procedure TIdCalculateSizeStream.IdSetSize(ASize: Int64);
begin
if ASize < 0 then begin
ASize := 0;
end;
if FSize <> ASize then begin
FSize := ASize;
if FSize < FPosition then begin
FPosition := FSize;
end;
end;
end;
function TIdEventStream.IdRead(var VBuffer: TIdBytes; AOffset, ACount: Longint): Longint;
begin
Result := 0;
if Assigned(FOnRead) then begin
FOnRead(VBuffer, AOffset, ACount, Result);
end;
end;
function TIdEventStream.IdWrite(const ABuffer: TIdBytes; AOffset, ACount: Longint): Longint;
begin
if Assigned(FOnWrite) then begin
Result := 0;
FOnWrite(ABuffer, AOffset, ACount, Result);
end else begin
Result := ACount;
end;
end;
function TIdEventStream.IdSeek(const AOffset: Int64; AOrigin: TSeekOrigin): Int64;
begin
Result := 0;
if Assigned(FOnSeek) then begin
FOnSeek(AOffset, AOrigin, Result);
end;
end;
procedure TIdEventStream.IdSetSize(ASize: Int64);
begin
if Assigned(FOnSetSize) then begin
FOnSetSize(ASize);
end;
end;
{$IFNDEF DOTNET}
constructor TIdMemoryBufferStream.Create(APtr: Pointer; ASize: TIdNativeInt);
begin
inherited Create;
SetPointer(APtr, ASize);
end;
function TIdMemoryBufferStream.Write(const Buffer; Count: Longint): Longint;
var
LNumToCopy: Longint;
begin
Result := 0;
if (Position >= 0) and (Size > 0) and (Count > 0) then
begin
LNumToCopy := IndyMin(Size - Position, Count);
if LNumToCopy > 0 then
begin
System.Move(Buffer, Pointer(PtrUInt(Memory) + Position)^, LNumToCopy);
TIdStreamHelper.Seek(Self, LNumToCopy, soCurrent);
Result := LNumToCopy;
end;
end;
end;
{$ENDIF}
procedure AppendBytes(var VBytes: TIdBytes; const AToAdd: TIdBytes; const AIndex: Integer = 0; const ALength: Integer = -1);
var
LOldLen, LAddLen: Integer;
begin
LAddLen := IndyLength(AToAdd, ALength, AIndex);
if LAddLen > 0 then begin
LOldLen := Length(VBytes);
SetLength(VBytes, LOldLen + LAddLen);
CopyTIdBytes(AToAdd, AIndex, VBytes, LOldLen, LAddLen);
end;
end;
procedure AppendByte(var VBytes: TIdBytes; const AByte: Byte);
var
LOldLen: Integer;
begin
LOldLen := Length(VBytes);
SetLength(VBytes, LOldLen + 1);
VBytes[LOldLen] := AByte;
end;
procedure AppendString(var VBytes: TIdBytes; const AStr: String; const ALength: Integer = -1;
ADestEncoding: IIdTextEncoding = nil
{$IFDEF STRING_IS_ANSI}; ASrcEncoding: IIdTextEncoding = nil{$ENDIF}
);
var
LBytes: TIdBytes;
LLength, LOldLen: Integer;
begin
LBytes := nil; // keep the compiler happy
LLength := IndyLength(AStr, ALength);
if LLength > 0 then begin
LBytes := ToBytes(AStr, LLength, 1, ADestEncoding
{$IFDEF STRING_IS_ANSI}, ASrcEncoding{$ENDIF}
);
LOldLen := Length(VBytes);
LLength := Length(LBytes);
SetLength(VBytes, LOldLen + LLength);
CopyTIdBytes(LBytes, 0, VBytes, LOldLen, LLength);
end;
end;
procedure ExpandBytes(var VBytes: TIdBytes; const AIndex: Integer; const ACount: Integer; const AFillByte: Byte = 0);
var
I: Integer;
begin
if ACount > 0 then begin
// if AIndex is at the end of the buffer then the operation is appending bytes
if AIndex <> Length(VBytes) then begin
//if these asserts fail, then it indicates an attempted buffer overrun.
Assert(AIndex >= 0);
Assert(AIndex < Length(VBytes));
end;
SetLength(VBytes, Length(VBytes) + ACount);
// move any existing bytes at the index to the end of the buffer
for I := Length(VBytes)-1 downto AIndex+ACount do begin
VBytes[I] := VBytes[I-ACount];
end;
// fill in the new space with the fill byte
for I := AIndex to AIndex+ACount-1 do begin
VBytes[I] := AFillByte;
end;
end;
end;
procedure InsertBytes(var VBytes: TIdBytes; const ADestIndex: Integer;
const ASource: TIdBytes; const ASourceIndex: Integer = 0);
var
LAddLen: Integer;
begin
LAddLen := IndyLength(ASource, -1, ASourceIndex);
if LAddLen > 0 then begin
ExpandBytes(VBytes, ADestIndex, LAddLen);
CopyTIdBytes(ASource, ASourceIndex, VBytes, ADestIndex, LAddLen);
end;
end;
procedure InsertByte(var VBytes: TIdBytes; const AByte: Byte; const AIndex: Integer);
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
ExpandBytes(VBytes, AIndex, 1, AByte);
end;
procedure RemoveBytes(var VBytes: TIdBytes; const ACount: Integer; const AIndex: Integer = 0);
var
I: Integer;
LActual: Integer;
begin
Assert(AIndex >= 0);
LActual := IndyMin(Length(VBytes)-AIndex, ACount);
if LActual > 0 then begin
if (AIndex + LActual) < Length(VBytes) then begin
// RLebeau: TODO - use Move() here instead?
for I := AIndex to Length(VBytes)-LActual-1 do begin
VBytes[I] := VBytes[I+LActual];
end;
end;
SetLength(VBytes, Length(VBytes)-LActual);
end;
end;
procedure IdDelete(var s: string; AOffset, ACount: Integer);
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Delete(s, AOffset, ACount);
end;
procedure IdInsert(const Source: string; var S: string; Index: Integer);
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Insert(Source, S, Index);
end;
function TextIsSame(const A1, A2: string): Boolean;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
{$IFDEF DOTNET}
Result := System.String.Compare(A1, A2, True) = 0;
{$ELSE}
Result := AnsiCompareText(A1, A2) = 0;
{$ENDIF}
end;
function TextStartsWith(const S, SubS: string): Boolean;
var
LLen: Integer;
{$IFDEF WINDOWS}
{$IFDEF STRING_UNICODE_MISMATCH}
LS, LSub: TIdPlatformString;
P1, P2: PIdPlatformChar;
{$ELSE}
P1, P2: PChar;
{$ENDIF}
{$ENDIF}
begin
LLen := Length(SubS);
Result := LLen <= Length(S);
if Result then
begin
{$IFDEF DOTNET}
Result := System.String.Compare(S, 0, SubS, 0, LLen, True) = 0;
{$ELSE}
{$IFDEF WINDOWS}
{$IFDEF STRING_UNICODE_MISMATCH}
// explicit convert to Ansi/Unicode
LS := TIdPlatformString(S);
LSub := TIdPlatformString(SubS);
P1 := PIdPlatformChar(LS);
P2 := PIdPlatformChar(LSub);
{$ELSE}
P1 := PChar(S);
P2 := PChar(SubS);
{$ENDIF}
Result := CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, P1, LLen, P2, LLen) = 2;
{$ELSE}
Result := AnsiCompareText(Copy(S, 1, LLen), SubS) = 0;
{$ENDIF}
{$ENDIF}
end;
end;
function TextEndsWith(const S, SubS: string): Boolean;
var
LLen: Integer;
{$IFDEF WINDOWS}
{$IFDEF STRING_UNICODE_MISMATCH}
LS, LSubS: TIdPlatformString;
P1, P2: PIdPlatformChar;
{$ELSE}
P1, P2: PChar;
{$ENDIF}
{$ENDIF}
begin
LLen := Length(SubS);
Result := LLen <= Length(S);
if Result then
begin
{$IFDEF DOTNET}
Result := System.String.Compare(S, Length(S)-LLen, SubS, 0, LLen, True) = 0;
{$ELSE}
{$IFDEF WINDOWS}
{$IFDEF STRING_UNICODE_MISMATCH}
// explicit convert to Ansi/Unicode
LS := TIdPlatformString(S);
LSubS := TIdPlatformString(SubS);
P1 := PIdPlatformChar(LS);
P2 := PIdPlatformChar(LSubS);
{$ELSE}
P1 := PChar(S);
P2 := PChar(SubS);
{$ENDIF}
Inc(P1, Length(S)-LLen);
Result := CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, P1, LLen, P2, LLen) = 2;
{$ELSE}
Result := AnsiCompareText(Copy(S, Length(S)-LLen+1, LLen), SubS) = 0;
{$ENDIF}
{$ENDIF}
end;
end;
function IndyLowerCase(const A1: string): string;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
{$IFDEF DOTNET}
Result := A1.ToLower;
{$ELSE}
Result := AnsiLowerCase(A1);
{$ENDIF}
end;
function IndyUpperCase(const A1: string): string;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
{$IFDEF DOTNET}
Result := A1.ToUpper;
{$ELSE}
Result := AnsiUpperCase(A1);
{$ENDIF}
end;
function IndyCompareStr(const A1, A2: string): Integer;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
{$IFDEF DOTNET}
Result := CompareStr(A1, A2);
{$ELSE}
Result := AnsiCompareStr(A1, A2);
{$ENDIF}
end;
function CharPosInSet(const AString: string; const ACharPos: Integer; const ASet: String): Integer;
{$IFDEF USE_INLINE}inline;{$ENDIF}
{$IFNDEF DOTNET}
var
LChar: Char;
I: Integer;
{$ENDIF}
begin
Result := 0;
if ACharPos < 1 then begin
raise EIdException.Create('Invalid ACharPos');{ do not localize }
end;
if ACharPos <= Length(AString) then begin
{$IFDEF DOTNET}
Result := ASet.IndexOf(AString[ACharPos]) + 1;
{$ELSE}
// RLebeau 5/8/08: Calling Pos() with a Char as input creates a temporary
// String. Normally this is fine, but profiling reveils this to be a big
// bottleneck for code that makes a lot of calls to CharIsInSet(), so need
// to scan through ASet looking for the character without a conversion...
//
// Result := IndyPos(AString[ACharPos], ASet);
//
LChar := AString[ACharPos];
for I := 1 to Length(ASet) do begin
if ASet[I] = LChar then begin
Result := I;
Exit;
end;
end;
{$ENDIF}
end;
end;
function CharIsInSet(const AString: string; const ACharPos: Integer; const ASet: String): Boolean;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Result := CharPosInSet(AString, ACharPos, ASet) > 0;
end;
function CharIsInEOL(const AString: string; const ACharPos: Integer): Boolean;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Result := CharPosInSet(AString, ACharPos, EOL) > 0;
end;
function CharEquals(const AString: string; const ACharPos: Integer; const AValue: Char): Boolean;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
if ACharPos < 1 then begin
raise EIdException.Create('Invalid ACharPos');{ do not localize }
end;
Result := ACharPos <= Length(AString);
if Result then begin
Result := AString[ACharPos] = AValue;
end;
end;
{$IFDEF STRING_IS_IMMUTABLE}
{$IFDEF DOTNET}
{$DEFINE HAS_String_IndexOf}
{$ENDIF}
{$IFDEF HAS_SysUtils_TStringHelper}
{$DEFINE HAS_String_IndexOf}
{$ENDIF}
function CharPosInSet(const ASB: TIdStringBuilder; const ACharPos: Integer; const ASet: String): Integer;
{$IFDEF USE_INLINE}inline;{$ENDIF}
{$IFNDEF HAS_String_IndexOf}
var
LChar: Char;
I: Integer;
{$ENDIF}
begin
Result := 0;
if ACharPos < 1 then begin
raise EIdException.Create('Invalid ACharPos');{ do not localize }
end;
if ACharPos <= ASB.Length then begin
{$IFDEF HAS_String_IndexOf}
Result := ASet.IndexOf(ASB[ACharPos-1]) + 1;
{$ELSE}
// RLebeau 5/8/08: Calling Pos() with a Char as input creates a temporary
// String. Normally this is fine, but profiling reveils this to be a big
// bottleneck for code that makes a lot of calls to CharIsInSet(), so need
// to scan through ASet looking for the character without a conversion...
//
// Result := IndyPos(ASB[ACharPos-1], ASet);
//
LChar := ASB[ACharPos-1];
for I := 1 to Length(ASet) do begin
if ASet[I] = LChar then begin
Result := I;
Exit;
end;
end;
{$ENDIF}
end;
end;
function CharIsInSet(const ASB: TIdStringBuilder; const ACharPos: Integer; const ASet: String): Boolean;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Result := CharPosInSet(ASB, ACharPos, ASet) > 0;
end;
function CharIsInEOL(const ASB: TIdStringBuilder; const ACharPos: Integer): Boolean;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Result := CharPosInSet(ASB, ACharPos, EOL) > 0;
end;
function CharEquals(const ASB: TIdStringBuilder; const ACharPos: Integer; const AValue: Char): Boolean;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
if ACharPos < 1 then begin
raise EIdException.Create('Invalid ACharPos');{ do not localize }
end;
Result := ACharPos <= ASB.Length;
if Result then begin
Result := ASB[ACharPos-1] = AValue;
end;
end;
{$ENDIF}
function ByteIndex(const AByte: Byte; const ABytes: TIdBytes; const AStartIndex: Integer = 0): Integer;
var
I: Integer;
begin
Result := -1;
for I := AStartIndex to Length(ABytes)-1 do begin
if ABytes[I] = AByte then begin
Result := I;
Exit;
end;
end;
end;
function ByteIdxInSet(const ABytes: TIdBytes; const AIndex: Integer; const ASet: TIdBytes): Integer;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
if AIndex < 0 then begin
raise EIdException.Create('Invalid AIndex'); {do not localize}
end;
if AIndex < Length(ABytes) then begin
Result := ByteIndex(ABytes[AIndex], ASet);
end else begin
Result := -1;
end;
end;
function ByteIsInSet(const ABytes: TIdBytes; const AIndex: Integer; const ASet: TIdBytes): Boolean;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
Result := ByteIdxInSet(ABytes, AIndex, ASet) > -1;
end;
function ByteIsInEOL(const ABytes: TIdBytes; const AIndex: Integer): Boolean;
var
LSet: TIdBytes;
begin
SetLength(LSet, 2);
LSet[0] := 13;
LSet[1] := 10;
Result := ByteIsInSet(ABytes, AIndex, LSet);
end;
function ReadLnFromStream(AStream: TStream; AMaxLineLength: Integer = -1;
AExceptionIfEOF: Boolean = False; AByteEncoding: IIdTextEncoding = nil
{$IFDEF STRING_IS_ANSI}; ADestEncoding: IIdTextEncoding = nil{$ENDIF}
): string; overload;
begin
if (not ReadLnFromStream(AStream, Result, AMaxLineLength, AByteEncoding
{$IFDEF STRING_IS_ANSI}, ADestEncoding{$ENDIF}
)) and AExceptionIfEOF then
begin
raise EIdEndOfStream.CreateFmt(RSEndOfStream, ['ReadLnFromStream', AStream.Position]);
end;
end;
//TODO: Continue to optimize this function. Its performance severely impacts the coders
function ReadLnFromStream(AStream: TStream; var VLine: String; AMaxLineLength: Integer = -1;
AByteEncoding: IIdTextEncoding = nil
{$IFDEF STRING_IS_ANSI}; ADestEncoding: IIdTextEncoding = nil{$ENDIF}
): Boolean; overload;
const
LBUFMAXSIZE = 2048;
var
LStringLen, LResultLen, LBufSize: Integer;
LBuf: TIdBytes;
LLine: TIdBytes;
// LBuf: packed array [0..LBUFMAXSIZE] of Char;
LStrmPos, LStrmSize: TIdStreamSize; //LBytesToRead = stream size - Position
LCrEncountered: Boolean;
function FindEOL(const ABuf: TIdBytes; var VLineBufSize: Integer; var VCrEncountered: Boolean): Integer;
var
i: Integer;
begin
Result := VLineBufSize; //EOL not found => use all
i := 0;
while i < VLineBufSize do begin
case ABuf[i] of
Ord(LF): begin
Result := i; {string size}
VCrEncountered := True;
VLineBufSize := i+1;
Break;
end;
Ord(CR): begin
Result := i; {string size}
VCrEncountered := True;
Inc(i); //crLF?
if (i < VLineBufSize) and (ABuf[i] = Ord(LF)) then begin
VLineBufSize := i+1;
end else begin
VLineBufSize := i;
end;
Break;
end;
end;
Inc(i);
end;
end;
begin
Assert(AStream<>nil);
VLine := '';
SetLength(LLine, 0);
if AMaxLineLength < 0 then begin
AMaxLineLength := MaxInt;
end;
{ we store the stream size for the whole routine to prevent
so do not incur a performance penalty with TStream.Size. It has
to use something such as Seek each time the size is obtained}
{4 seek vs 3 seek}
LStrmPos := AStream.Position;
LStrmSize := AStream.Size;
if LStrmPos >= LStrmSize then begin
Result := False;
Exit;
end;
SetLength(LBuf, LBUFMAXSIZE);
LCrEncountered := False;
repeat
LBufSize := ReadTIdBytesFromStream(AStream, LBuf, IndyMin(LStrmSize - LStrmPos, LBUFMAXSIZE));
if LBufSize < 1 then begin
Break; // TODO: throw a stream read exception instead?
end;
LStringLen := FindEOL(LBuf, LBufSize, LCrEncountered);
Inc(LStrmPos, LBufSize);
LResultLen := Length(VLine);
if (LResultLen + LStringLen) > AMaxLineLength then begin
LStringLen := AMaxLineLength - LResultLen;
LCrEncountered := True;
Dec(LStrmPos, LBufSize);
Inc(LStrmPos, LStringLen);
end;
if LStringLen > 0 then begin
LBufSize := Length(LLine);
SetLength(LLine, LBufSize+LStringLen);
CopyTIdBytes(LBuf, 0, LLine, LBufSize, LStringLen);
end;
until (LStrmPos >= LStrmSize) or LCrEncountered;
// RLebeau: why is the original Position being restored here, instead
// of leaving the Position at the end of the line?
AStream.Position := LStrmPos;
VLine := BytesToString(LLine, 0, -1, AByteEncoding
{$IFDEF STRING_IS_ANSI}, ADestEncoding{$ENDIF}
);
Result := True;
end;
{$IFNDEF DOTNET}
{$IFDEF REGISTER_EXPECTED_MEMORY_LEAK}
function IndyRegisterExpectedMemoryLeak(AAddress: Pointer): Boolean;
{$IFDEF USE_INLINE}inline;{$ENDIF}
begin
// TODO: use only System.RegisterExpectedMemoryLeak() on systems that support
// it. We should use whatever the RTL's active memory manager is. Fallback
// to specific memory managers only if System.RegisterExpectedMemoryLeak()
// is not available.
{$IFDEF USE_FASTMM4}
// RLebeau 4/9/2009: the user can override the RTL's version of FastMM
// (2006+ only) with the full version of FastMM in order to enable
// advanced debugging features, so check for that first...
Result := FastMM4.RegisterExpectedMemoryLeak(AAddress);
{$ELSE}
{$IFDEF USE_MADEXCEPT}
// RLebeau 10/5/2014: the user can override the RTL's version of FastMM
// (2006+ only) with any memory manager, such as MadExcept, so check for
// that next...
Result := madExcept.HideLeak(AAddress);
{$ELSE}
{$IFDEF HAS_System_RegisterExpectedMemoryLeak}
// RLebeau 4/21/08: not quite sure what the difference is between the
// SysRegisterExpectedMemoryLeak() and RegisterExpectedMemoryLeak()
// functions in the System unit, but calling RegisterExpectedMemoryLeak()
// is causing stack overflows when FastMM is not active, so call
// SysRegisterExpectedMemoryLeak() instead...
// RLebeau 7/4/09: According to Pierre Le Riche, developer of FastMM:
//
// "SysRegisterExpectedMemoryLeak() is the leak registration routine for
// the built-in memory manager. FastMM.RegisterExpectedMemoryLeak is the
// leak registration code for FastMM. Both of these are thus hardwired to
// a specific memory manager. In order to register a leak for the
// *currently installed* memory manager, which is what you typically want
// to do, you have to call System.RegisterExpectedMemoryLeak().
// System.RegisterExpectedMemoryLeak() redirects to the leak registration
// code of the installed memory manager."
//Result := System.SysRegisterExpectedMemoryLeak(AAddress);
Result := System.RegisterExpectedMemoryLeak(AAddress);
{$ELSE}
Result := False;
{$ENDIF}
{$ENDIF}
{$ENDIF}
end;
{$ENDIF}
{$ENDIF}
function InternalIndyIndexOf(AStrings: TStrings; const AStr: string;
const ACaseSensitive: Boolean = False): Integer;
{$IFDEF USE_INLINE}inline;{$ENDIF}
var
I: Integer;
begin
Result := -1;
for I := 0 to AStrings.Count - 1 do begin
if ACaseSensitive then begin
if AStrings[I] = AStr then begin
Result := I;
Exit;
end;
end else begin
if TextIsSame(AStrings[I], AStr) then begin
Result := I;
Exit;
end;
end;
end;
end;
function IndyIndexOf(AStrings: TStrings; const AStr: string;
const ACaseSensitive: Boolean = False): Integer;
begin
{$IFDEF HAS_TStringList_CaseSensitive}
if AStrings is TStringList then begin
Result := IndyIndexOf(TStringList(AStrings), AStr, ACaseSensitive);
Exit;
end;
{$ENDIF}
Result := InternalIndyIndexOf(AStrings, AStr, ACaseSensitive);
end;
{$IFDEF HAS_TStringList_CaseSensitive}
function IndyIndexOf(AStrings: TStringList; const AStr: string;
const ACaseSensitive: Boolean = False): Integer;
begin
if AStrings.CaseSensitive = ACaseSensitive then begin
Result := AStrings.IndexOf(AStr);
end else begin
Result := InternalIndyIndexOf(AStrings, AStr, ACaseSensitive);
end;
end;
{$ENDIF}
function InternalIndyIndexOfName(AStrings: TStrings; const AStr: string;
const ACaseSensitive: Boolean = False): Integer;
{$IFDEF USE_INLINE}inline;{$ENDIF}
var
I: Integer;
begin
Result := -1;
for I := 0 to AStrings.Count - 1 do begin
if ACaseSensitive then begin
if AStrings.Names[I] = AStr then begin
Result := I;
Exit;
end;
end else begin
if TextIsSame(AStrings.Names[I], AStr) then begin
Result := I;
Exit;
end;
end;
end;
end;
function IndyIndexOfName(AStrings: TStrings; const AStr: string;
const ACaseSensitive: Boolean = False): Integer;
begin
{$IFDEF HAS_TStringList_CaseSensitive}
if AStrings is TStringList then begin
Result := IndyIndexOfName(TStringList(AStrings), AStr, ACaseSensitive);
Exit;
end;
{$ENDIF}
Result := InternalIndyIndexOfName(AStrings, AStr, ACaseSensitive);
end;
{$IFDEF HAS_TStringList_CaseSensitive}
function IndyIndexOfName(AStrings: TStringList; const AStr: string;
const ACaseSensitive: Boolean = False): Integer;
begin
if AStrings.CaseSensitive = ACaseSensitive then begin
Result := AStrings.IndexOfName(AStr);
end else begin
Result := InternalIndyIndexOfName(AStrings, AStr, ACaseSensitive);
end;
end;
{$ENDIF}
function IndyValueFromIndex(AStrings: TStrings; const AIndex: Integer): String;
{$IFNDEF HAS_TStrings_ValueFromIndex}
var
LTmp: string;
LPos: Integer;
{$ENDIF}
begin
{$IFDEF HAS_TStrings_ValueFromIndex}
Result := AStrings.ValueFromIndex[AIndex];
{$ELSE}
Result := '';
if AIndex >= 0 then
begin
LTmp := AStrings.Strings[AIndex];
// TODO: use AStrings.NameValueSeparator on platforms that support it
LPos := Pos('=', LTmp); {do not localize}
if LPos > 0 then begin
Result := Copy(LTmp, LPos+1, MaxInt);
Exit;
end;
end;
{$ENDIF}
end;
{$IFDEF WINDOWS}
function IndyWindowsMajorVersion: Integer;
begin
{$IFDEF WINCE}
Result := SysUtils.WinCEMajorVersion;
{$ELSE}
Result := SysUtils.Win32MajorVersion;
{$ENDIF}
end;
function IndyWindowsMinorVersion: Integer;
begin
{$IFDEF WINCE}
Result := SysUtils.WinCEMinorVersion;
{$ELSE}
Result := SysUtils.Win32MinorVersion;
{$ENDIF}
end;
function IndyWindowsBuildNumber: Integer;
begin
// for this, you need to strip off some junk to do comparisons
{$IFDEF WINCE}
Result := SysUtils.WinCEBuildNumber and $FFFF;
{$ELSE}
Result := SysUtils.Win32BuildNumber and $FFFF;
{$ENDIF}
end;
function IndyWindowsPlatform: Integer;
begin
{$IFDEF WINCE}
Result := SysUtils.WinCEPlatform;
{$ELSE}
Result := SysUtils.Win32Platform;
{$ENDIF}
end;
function IndyCheckWindowsVersion(const AMajor: Integer; const AMinor: Integer = 0): Boolean;
var
LMajor, LMinor: Integer;
begin
LMajor := IndyWindowsMajorVersion;
LMinor := IndyWindowsMinorVersion;
Result := (LMajor > AMajor) or ((LMajor = AMajor) and (LMinor >= AMinor));
end;
{$ENDIF}
procedure IdDisposeAndNil(var Obj);
{$IFDEF USE_OBJECT_ARC}
var
Temp: {Pointer}TObject;
{$ENDIF}
begin
{$IFDEF USE_OBJECT_ARC}
// RLebeau: was originally calling DisposeOf() on Obj directly, but nil'ing
// Obj first prevented the calling code from invoking __ObjRelease() on Obj.
// Don't do that in ARC. __ObjRelease() needs to be called, even if disposed,
// to allow the compiler/RTL to finalize Obj so any managed members it has
// can be cleaned up properly...
{
Temp := Pointer(Obj);
Pointer(Obj) := nil;
TObject(Temp).DisposeOf;
}
Pointer(Temp) := Pointer(Obj);
Pointer(Obj) := nil;
Temp.DisposeOf;
// __ObjRelease() is called when Temp goes out of scope
{$ELSE}
FreeAndNil(Obj);
{$ENDIF}
end;
initialization
// AnsiPos does not handle strings with #0 and is also very slow compared to Pos
{$IFDEF DOTNET}
IndyPos := SBPos;
{$ELSE}
if LeadBytes = [] then begin
IndyPos := SBPos;
end else begin
IndyPos := InternalAnsiPos;
end;
{$ENDIF}
{$IFDEF DYNAMICLOAD_InterlockedCompareExchange}
InterlockedCompareExchange := Stub_InterlockedCompareExchange;
{$ENDIF}
{$IFDEF WINDOWS}
GetTickCount64 := Stub_GetTickCount64;
{$ENDIF}
{$IFDEF UNIX}
{$IFDEF DARWIN}
mach_timebase_info(GMachTimeBaseInfo);
{$ENDIF}
{$ENDIF}
{$IFNDEF DOTNET}
finalization
FreeAndNil(GIdPorts);
{$ENDIF}
end.