/indy/IdGlobal.pas

https://code.google.com/ · Pascal · 7040 lines · 4489 code · 543 blank · 2008 comment · 406 complexity · 2de30d128dea2ed10427c4a1b9042726 MD5 · raw file

  1. {
  2. $Project$
  3. $Workfile$
  4. $Revision$
  5. $DateUTC$
  6. $Id$
  7. This file is part of the Indy (Internet Direct) project, and is offered
  8. under the dual-licensing agreement described on the Indy website.
  9. (http://www.indyproject.org/)
  10. Copyright:
  11. (c) 1993-2005, Chad Z. Hower and the Indy Pit Crew. All rights reserved.
  12. }
  13. {
  14. $Log$
  15. }
  16. {
  17. Rev 1.54 2/9/2005 8:45:38 PM JPMugaas
  18. Should work.
  19. Rev 1.53 2/8/05 6:37:38 PM RLebeau
  20. Added default value to ASize parameter of ReadStringFromStream()
  21. Rev 1.52 2/8/05 5:57:10 PM RLebeau
  22. added AppendString(), CopyTIdLongWord(), and CopyTIdString() functions
  23. Rev 1.51 1/31/05 6:01:40 PM RLebeau
  24. Renamed GetCurrentThreadHandle() to CurrentThreadId() and changed the return
  25. type from THandle to to TIdPID.
  26. Reworked conditionals for SetThreadName() and updated the implementation to
  27. support naming threads under DotNet.
  28. Rev 1.50 1/27/05 3:40:04 PM RLebeau
  29. Updated BytesToShort() to actually use the AIndex parameter that was added
  30. earlier.
  31. Rev 1.49 1/24/2005 7:35:36 PM JPMugaas
  32. Foxed ma,e om CopyTIdIPV6Address/
  33. Rev 1.48 1/17/2005 7:26:44 PM JPMugaas
  34. Made an IPv6 address byte copy function.
  35. Rev 1.47 1/15/2005 6:01:38 PM JPMugaas
  36. Removed some new procedures for extracting int values from a TIdBytes and
  37. made some other procedures have an optional index paramter.
  38. Rev 1.46 1/13/05 11:11:20 AM RLebeau
  39. Changed BytesToRaw() to pass TIdBytes by 'const' rather than by 'var'
  40. Rev 1.45 1/8/2005 3:56:58 PM JPMugaas
  41. Added routiens for copying integer values to and from TIdBytes. These are
  42. useful for some protocols.
  43. Rev 1.44 24/11/2004 16:26:24 ANeillans
  44. GetTickCount corrected, as per Paul Cooper's post in
  45. atozedsoftware.indy.general.
  46. Rev 1.43 11/13/04 10:47:28 PM RLebeau
  47. Fixed compiler errors
  48. Rev 1.42 11/12/04 1:02:42 PM RLebeau
  49. Added RawToBytesF() and BytesToRaw() functions
  50. Added asserts to BytesTo...() functions
  51. Rev 1.41 10/26/2004 8:20:02 PM JPMugaas
  52. Fixed some oversights with conversion. OOPS!!!
  53. Rev 1.40 10/26/2004 8:00:54 PM JPMugaas
  54. Now uses TIdStrings for DotNET portability.
  55. Rev 1.39 2004.10.26 7:35:16 PM czhower
  56. Moved IndyCat to CType in IdBaseComponent
  57. Rev 1.38 24/10/2004 21:29:52 ANeillans
  58. Corrected error in GetTickCount,
  59. was Result := Trunc(nTime / (Freq * 1000))
  60. should be Result := Trunc((nTime / Freq) * 1000)
  61. Rev 1.37 20/10/2004 01:08:20 CCostelloe
  62. Bug fix
  63. Rev 1.36 28.09.2004 20:36:58 Andreas Hausladen
  64. Works now with Delphi 5
  65. Rev 1.35 9/23/2004 11:36:04 PM DSiders
  66. Modified Ticks function (Win32) to correct RangeOverflow error. (Reported by
  67. Mike Potter)
  68. Rev 1.34 24.09.2004 02:16:04 Andreas Hausladen
  69. Added ReadTIdBytesFromStream and ReadCharFromStream function to supress .NET
  70. warnings.
  71. Rev 1.33 9/5/2004 2:55:00 AM JPMugaas
  72. function BytesToWord(const AValue: TIdBytes): Word; was not listed in the
  73. interface.
  74. Rev 1.32 04.09.2004 17:12:56 Andreas Hausladen
  75. New PosIdx function (without pointers)
  76. Rev 1.31 27.08.2004 22:02:20 Andreas Hausladen
  77. Speed optimization ("const" for string parameters)
  78. rewritten PosIdx function with AStartPos = 0 handling
  79. new ToArrayF() functions (faster in native code because the TIdBytes array
  80. must have the required len before the ToArrayF function is called)
  81. Rev 1.30 24.08.2004 19:48:28 Andreas Hausladen
  82. Some optimizations
  83. Removed IFDEF for IdDelete and IdInsert
  84. Rev 1.29 8/17/2004 2:54:08 PM JPMugaas
  85. Fix compiler warning about widening operends. Int64 can sometimes incur a
  86. performance penalty.
  87. Rev 1.28 8/15/04 5:57:06 PM RLebeau
  88. Tweaks to PosIdx()
  89. Rev 1.27 7/23/04 10:13:16 PM RLebeau
  90. Updated ReadStringFromStream() to resize the result using the actual number
  91. of bytes read from the stream
  92. Rev 1.26 7/18/2004 2:45:38 PM DSiders
  93. Added localization comments.
  94. Rev 1.25 7/9/04 4:25:20 PM RLebeau
  95. Renamed ToBytes(raw) to RawToBytes() to fix an ambiquity error with
  96. ToBytes(TIdBytes)
  97. Rev 1.24 7/9/04 4:07:06 PM RLebeau
  98. Compiler fix for TIdBaseStream.Write()
  99. Rev 1.23 09/07/2004 22:17:52 ANeillans
  100. Fixed IdGlobal.pas(761) Error: ';', ')' or '=' expected but ':=' found
  101. Rev 1.22 7/8/04 11:56:10 PM RLebeau
  102. Added additional parameters to BytesToString()
  103. Bug fix for ReadStringFromStream()
  104. Updated TIdBaseStream.Write() to use ToBytes()
  105. Rev 1.21 7/8/04 4:22:36 PM RLebeau
  106. Added ToBytes() overload for raw pointers under non-DotNet platfoms.
  107. Rev 1.20 2004.07.03 19:39:38 czhower
  108. UTF8
  109. Rev 1.19 6/15/2004 7:18:06 PM JPMugaas
  110. IdInsert for stuff needing to call the Insert procedure.
  111. Rev 1.18 2004.06.13 8:06:46 PM czhower
  112. .NET update
  113. Rev 1.17 6/11/2004 8:28:30 AM DSiders
  114. Added "Do not Localize" comments.
  115. Rev 1.16 2004.06.08 7:11:14 PM czhower
  116. Typo fix.
  117. Rev 1.15 2004.06.08 6:34:48 PM czhower
  118. .NET bug with Ticks workaround.
  119. Rev 1.14 07/06/2004 21:30:32 CCostelloe
  120. Kylix 3 changes
  121. Rev 1.13 5/3/04 12:17:44 PM RLebeau
  122. Updated ToBytes(string) and BytesToString() under DotNet to use
  123. System.Text.Encoding.ASCII instead of AnsiEncoding
  124. Rev 1.12 4/24/04 12:41:36 PM RLebeau
  125. Conversion support to/from TIdBytes for Char values
  126. Rev 1.11 4/18/04 2:45:14 PM RLebeau
  127. Conversion support to/from TIdBytes for Int64 values
  128. Rev 1.10 2004.04.08 4:50:06 PM czhower
  129. Comments
  130. Rev 1.9 2004.04.08 1:45:42 AM czhower
  131. tiny string optimization
  132. Rev 1.8 4/7/2004 3:20:50 PM JPMugaas
  133. PosIdx was not working in DotNET. In DotNET, it was returning a Pos value
  134. without adding the startvalue -1. It was throwing off the FTP list parsers.
  135. Two uneeded IFDEF's were removed.
  136. Rev 1.7 2004.03.13 5:51:28 PM czhower
  137. Fixed stack overflow in Sleep for .net
  138. Rev 1.6 3/6/2004 5:16:02 PM JPMugaas
  139. Bug 67 fixes. Do not write to const values.
  140. Rev 1.5 3/6/2004 4:54:12 PM JPMugaas
  141. Write to const bug fix.
  142. Rev 1.4 2/17/2004 12:02:44 AM JPMugaas
  143. A few routines that might be needed later for RFC 3490 support.
  144. Rev 1.3 2/16/2004 1:56:04 PM JPMugaas
  145. Moved some routines here to lay the groundwork for RFC 3490 support. Started
  146. work on RFC 3490 support.
  147. Rev 1.2 2/11/2004 5:12:30 AM JPMugaas
  148. Moved IPv6 address definition here.
  149. I also made a function for converting a TIdBytes to an IPv6 address.
  150. Rev 1.1 2004.02.03 3:15:52 PM czhower
  151. Updates to move to System.
  152. Rev 1.0 2004.02.03 2:28:30 PM czhower
  153. Move
  154. Rev 1.91 2/1/2004 11:16:04 PM BGooijen
  155. ToBytes
  156. Rev 1.90 2/1/2004 1:28:46 AM JPMugaas
  157. Disabled IdPort functionality in DotNET. It can't work there in it's current
  158. form and trying to get it to work will introduce more problems than it
  159. solves. It was only used by the bindings editor and we did something
  160. different in DotNET so IdPorts wouldn't used there.
  161. Rev 1.89 2004.01.31 1:51:10 AM czhower
  162. IndyCast for VB.
  163. Rev 1.88 30/1/2004 4:47:46 PM SGrobety
  164. Added "WriteMemoryStreamToStream" to take care of Win32/dotnet difference in
  165. the TMemoryStream.Memory type and the Write buffer parameter
  166. Rev 1.87 1/30/2004 11:59:24 AM BGooijen
  167. Added WriteTIdBytesToStream, because we can convert almost everything to
  168. TIdBytes, and TIdBytes couldn't be written to streams easily
  169. Rev 1.86 2004.01.27 11:44:36 PM czhower
  170. .Net Updates
  171. Rev 1.85 2004.01.27 8:15:54 PM czhower
  172. Fixed compile error + .net helper.
  173. Rev 1.84 27/1/2004 1:55:10 PM SGrobety
  174. TIdStringStream introduced to fix a bug in DOTNET TStringStream
  175. implementation.
  176. Rev 1.83 2004.01.27 1:42:00 AM czhower
  177. Added parameter check
  178. Rev 1.82 25/01/2004 21:55:40 CCostelloe
  179. Added portable IdFromBeginning/FromCurrent/FromEnd, to be used instead of
  180. soFromBeginning/soBeginning, etc.
  181. Rev 1.81 24/01/2004 20:18:46 CCostelloe
  182. Added IndyCompareStr (to be used in place of AnsiCompareStr for .NET
  183. compatibility)
  184. Rev 1.80 2004.01.23 9:56:30 PM czhower
  185. CharIsInSet now checks length and returns false if no character.
  186. Rev 1.79 2004.01.23 9:49:40 PM czhower
  187. CharInSet no longer accepts -1, was unneeded and redundant.
  188. Rev 1.78 1/22/2004 5:47:46 PM SPerry
  189. fixed CharIsInSet
  190. Rev 1.77 2004.01.22 5:33:46 PM czhower
  191. TIdCriticalSection
  192. Rev 1.76 2004.01.22 3:23:18 PM czhower
  193. IsCharInSet
  194. Rev 1.75 2004.01.22 2:00:14 PM czhower
  195. iif change
  196. Rev 1.74 14/01/2004 00:17:34 CCostelloe
  197. Added IndyLowerCase/IndyUpperCase to replace AnsiLowerCase/AnsiUpperCase for
  198. .NET code
  199. Rev 1.73 1/11/2004 9:50:54 PM BGooijen
  200. Added ToBytes function for Socks
  201. Rev 1.72 2003.12.31 7:32:40 PM czhower
  202. InMainThread now for .net too.
  203. Rev 1.71 2003.12.29 6:48:38 PM czhower
  204. TextIsSame
  205. Rev 1.70 2003.12.28 1:11:04 PM czhower
  206. Conditional typo fixed.
  207. Rev 1.69 2003.12.28 1:05:48 PM czhower
  208. .Net changes.
  209. Rev 1.68 5/12/2003 9:11:00 AM GGrieve
  210. Add WriteStringToStream
  211. Rev 1.67 5/12/2003 12:32:48 AM GGrieve
  212. fix DotNet warnings
  213. Rev 1.66 22/11/2003 12:03:02 AM GGrieve
  214. fix IdMultiPathFormData.pas implementation
  215. Rev 1.65 11/15/2003 1:15:36 PM VVassiliev
  216. Move AppendByte from IdDNSCommon to IdCoreGlobal
  217. Rev 1.64 10/28/2003 8:43:48 PM BGooijen
  218. compiles, and removed call to setstring
  219. Rev 1.63 2003.10.24 10:44:50 AM czhower
  220. IdStream implementation, bug fixes.
  221. Rev 1.62 10/18/2003 4:53:18 PM BGooijen
  222. Added ToHex
  223. Rev 1.61 2003.10.17 6:17:24 PM czhower
  224. Some parts moved to stream
  225. Rev 1.60 10/15/2003 8:28:16 PM DSiders
  226. Added localization comments.
  227. Rev 1.59 2003.10.14 9:27:12 PM czhower
  228. Fixed compile erorr with missing )
  229. Rev 1.58 10/14/2003 3:31:04 PM SPerry
  230. Modified ByteToHex() and IPv4ToHex
  231. Rev 1.57 10/13/2003 5:06:46 PM BGooijen
  232. Removed local constant IdOctalDigits in favor of the unit constant. - attempt
  233. 2
  234. Rev 1.56 10/13/2003 10:07:12 AM DSiders
  235. Reverted prior change; local constant for IdOctalDigits is restored.
  236. Rev 1.55 10/12/2003 11:55:42 AM DSiders
  237. Removed local constant IdOctalDigits in favor of the unit constant.
  238. Rev 1.54 2003.10.11 5:47:22 PM czhower
  239. -VCL fixes for servers
  240. -Chain suport for servers (Super core)
  241. -Scheduler upgrades
  242. -Full yarn support
  243. Rev 1.53 10/8/2003 10:14:34 PM GGrieve
  244. add WriteStringToStream
  245. Rev 1.52 10/8/2003 9:55:30 PM GGrieve
  246. Add IdDelete
  247. Rev 1.51 10/7/2003 11:33:30 PM GGrieve
  248. Fix ReadStringFromStream
  249. Rev 1.50 10/7/2003 10:07:30 PM GGrieve
  250. Get IdHTTP compiling for DotNet
  251. Rev 1.49 6/10/2003 5:48:48 PM SGrobety
  252. DotNet updates
  253. Rev 1.48 10/5/2003 12:26:46 PM BGooijen
  254. changed parameter names at some places
  255. Rev 1.47 10/4/2003 7:08:26 PM BGooijen
  256. added some conversion routines type->TIdBytes->type, and fixed existing ones
  257. Rev 1.46 10/4/2003 3:53:40 PM BGooijen
  258. added some ToBytes functions
  259. Rev 1.45 04/10/2003 13:38:28 HHariri
  260. Write(Integer) support
  261. Rev 1.44 10/3/2003 10:44:54 PM BGooijen
  262. Added WriteBytesToStream
  263. Rev 1.43 2003.10.02 8:29:14 PM czhower
  264. Changed names of byte conversion routines to be more readily understood and
  265. not to conflict with already in use ones.
  266. Rev 1.42 10/2/2003 5:15:16 PM BGooijen
  267. Added Grahame's functions
  268. Rev 1.41 10/1/2003 8:02:20 PM BGooijen
  269. Removed some ifdefs and improved code
  270. Rev 1.40 2003.10.01 9:10:58 PM czhower
  271. .Net
  272. Rev 1.39 2003.10.01 2:46:36 PM czhower
  273. .Net
  274. Rev 1.38 2003.10.01 2:30:36 PM czhower
  275. .Net
  276. Rev 1.37 2003.10.01 12:30:02 PM czhower
  277. .Net
  278. Rev 1.35 2003.10.01 1:12:32 AM czhower
  279. .Net
  280. Rev 1.34 2003.09.30 7:37:14 PM czhower
  281. Typo fix.
  282. Rev 1.33 30/9/2003 3:58:08 PM SGrobety
  283. More .net updates
  284. Rev 1.31 2003.09.30 3:19:30 PM czhower
  285. Updates for .net
  286. Rev 1.30 2003.09.30 1:22:54 PM czhower
  287. Stack split for DotNet
  288. Rev 1.29 2003.09.30 12:09:36 PM czhower
  289. DotNet changes.
  290. Rev 1.28 2003.09.30 10:36:02 AM czhower
  291. Moved stack creation to IdStack
  292. Added DotNet stack.
  293. Rev 1.27 9/29/2003 03:03:28 PM JPMugaas
  294. Changed CIL to DOTNET.
  295. Rev 1.26 9/28/2003 04:22:00 PM JPMugaas
  296. IFDEF'ed out MemoryPos in NET because that will not work there.
  297. Rev 1.25 9/26/03 11:20:50 AM RLebeau
  298. Updated defines used with SetThreadName() to allow it to work under BCB6.
  299. Rev 1.24 9/24/2003 11:42:42 PM JPMugaas
  300. Minor changes to help compile under NET
  301. Rev 1.23 2003.09.20 10:25:42 AM czhower
  302. Added comment and chaned for D6 compat.
  303. Rev 1.22 9/18/2003 07:43:12 PM JPMugaas
  304. Moved GetThreadHandle to IdGlobals so the ThreadComponent can be in this
  305. package.
  306. Rev 1.21 9/8/2003 11:44:38 AM JPMugaas
  307. Fix for problem that was introduced in an optimization.
  308. Rev 1.20 2003.08.19 1:54:34 PM czhower
  309. Removed warning
  310. Rev 1.19 11/8/2003 6:25:44 PM SGrobety
  311. IPv4ToDWord: Added overflow checking disabling ($Q+) and changed "* 256" by
  312. "SHL 8".
  313. Rev 1.18 2003.07.08 2:41:42 PM czhower
  314. This time I saved the file before checking in.
  315. Rev 1.16 7/1/2003 03:39:38 PM JPMugaas
  316. Started numeric IP function API calls for more efficiency.
  317. Rev 1.15 2003.07.01 3:49:56 PM czhower
  318. Added SetThreadName
  319. Rev 1.14 7/1/2003 12:03:56 AM BGooijen
  320. Added functions to switch between IPv6 addresses in string and in
  321. TIdIPv6Address form
  322. Rev 1.13 6/30/2003 06:33:58 AM JPMugaas
  323. Fix for range check error.
  324. Rev 1.12 6/27/2003 04:43:30 PM JPMugaas
  325. Made IPv4ToDWord overload that returns a flag for an error message.
  326. Moved MakeCanonicalIPv4Address code into IPv4ToDWord because most of that
  327. simply reduces IPv4 addresses into a DWord. That also should make the
  328. function more useful in reducing various alternative forms of IPv4 addresses
  329. down to DWords.
  330. Rev 1.11 6/27/2003 01:19:38 PM JPMugaas
  331. Added MakeCanonicalIPv4Address for converting various IPv4 address forms
  332. (mentioned at http://www.pc-help.org/obscure.htm) into a standard dotted IP
  333. address. Hopefully, we should soon support octal and hexidecimal addresses.
  334. Rev 1.9 6/27/2003 04:36:08 AM JPMugaas
  335. Function for converting DWord to IP adcdress.
  336. Rev 1.8 6/26/2003 07:54:38 PM JPMugaas
  337. Routines for converting standard dotted IPv4 addresses into dword,
  338. hexidecimal, and octal forms.
  339. Rev 1.7 5/11/2003 11:57:06 AM BGooijen
  340. Added RaiseLastOSError
  341. Rev 1.6 4/28/2003 03:19:00 PM JPMugaas
  342. Made a function for obtaining the services file FQN. That's in case
  343. something else besides IdPorts needs it.
  344. Rev 1.5 2003.04.16 10:06:42 PM czhower
  345. Moved DebugOutput to IdCoreGlobal
  346. Rev 1.4 12/29/2002 2:15:30 PM JPMugaas
  347. GetCurrentThreadHandle function created as per Bas's instructions. Moved
  348. THandle to IdCoreGlobal for this function.
  349. Rev 1.3 12-15-2002 17:02:58 BGooijen
  350. Added comments to TIdExtList
  351. Rev 1.2 12-15-2002 16:45:42 BGooijen
  352. Added TIdList
  353. Rev 1.1 29/11/2002 10:08:50 AM SGrobety Version: 1.1
  354. Changed GetTickCount to use high-performance timer if available under windows
  355. Rev 1.0 21/11/2002 12:36:18 PM SGrobety Version: Indy 10
  356. Rev 1.0 11/13/2002 08:41:24 AM JPMugaas
  357. }
  358. unit IdGlobal;
  359. interface
  360. {$I IdCompilerDefines.inc}
  361. uses
  362. SysUtils,
  363. {$IFDEF DOTNET}
  364. System.Collections.Specialized,
  365. System.net,
  366. System.net.Sockets,
  367. System.Diagnostics,
  368. System.Threading,
  369. System.IO,
  370. System.Text,
  371. {$ENDIF}
  372. {$IFDEF WINDOWS}
  373. {$IFDEF FPC}
  374. windows,
  375. {$ELSE}
  376. Windows,
  377. {$ENDIF}
  378. {$ENDIF}
  379. Classes,
  380. syncobjs,
  381. {$IFDEF UNIX}
  382. {$IFDEF KYLIXCOMPAT}
  383. Libc,
  384. {$ELSE}
  385. {$IFDEF FPC}
  386. DynLibs, // better add DynLibs only for fpc
  387. {$ENDIF}
  388. {$IFDEF USE_VCL_POSIX}
  389. Posix.SysTypes, Posix.Pthread, Posix.Unistd,
  390. {$ENDIF}
  391. {$IFDEF USE_BASEUNIX}
  392. BaseUnix, Unix, Sockets, UnixType,
  393. {$ENDIF}
  394. {$IFDEF USE_ICONV_ENC}iconvenc, {$ENDIF}
  395. {$ENDIF}
  396. {$ENDIF}
  397. IdException;
  398. const
  399. {This is the only unit with references to OS specific units and IFDEFs. NO OTHER units
  400. are permitted to do so except .pas files which are counterparts to dfm/xfm files, and only for
  401. support of that.}
  402. //We make the version things an Inc so that they can be managed independantly
  403. //by the package builder.
  404. {$I IdVers.inc}
  405. {$IFNDEF HAS_TIMEUNITS}
  406. HoursPerDay = 24;
  407. MinsPerHour = 60;
  408. SecsPerMin = 60;
  409. MSecsPerSec = 1000;
  410. MinsPerDay = HoursPerDay * MinsPerHour;
  411. SecsPerDay = MinsPerDay * SecsPerMin;
  412. MSecsPerDay = SecsPerDay * MSecsPerSec;
  413. {$ENDIF}
  414. {$IFDEF DOTNET}
  415. // Timeout.Infinite is -1 which violates Cardinal which VCL uses for parameter
  416. // so we are just setting it to this as a hard coded constant until
  417. // the synchro classes and other are all ported directly to portable classes
  418. // (SyncObjs is platform specific)
  419. //Infinite = Timeout.Infinite;
  420. INFINITE = LongWord($FFFFFFFF); { Infinite timeout }
  421. {$ENDIF}
  422. {$IFDEF KYLIX}
  423. NilHandle = 0;
  424. {$ENDIF}
  425. {$IFDEF DELPHI}
  426. NilHandle = 0;
  427. {$ENDIF}
  428. LF = #10;
  429. CR = #13;
  430. // RLebeau: EOL is NOT to be used as a platform-specific line break! Most
  431. // text-based protocols that Indy implements are defined to use CRLF line
  432. // breaks. DO NOT change this! If you need a platform-based line break,
  433. // use sLineBreak instead.
  434. EOL = CR + LF;
  435. //
  436. CHAR0 = #0;
  437. BACKSPACE = #8;
  438. TAB = #9;
  439. CHAR32 = #32;
  440. //Timeout values
  441. IdTimeoutDefault = -1;
  442. IdTimeoutInfinite = -2;
  443. //Fetch Defaults
  444. IdFetchDelimDefault = ' '; {Do not Localize}
  445. IdFetchDeleteDefault = True;
  446. IdFetchCaseSensitiveDefault = True;
  447. IdWhiteSpace = [0..12, 14..32]; {do not localize}
  448. 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}
  449. IdOctalDigits: array [0..7] of Char = ('0','1','2','3','4','5','6','7'); {do not localize}
  450. IdHexPrefix = '0x'; {Do not translate}
  451. type
  452. //thread and PID stuff
  453. {$IFDEF DOTNET}
  454. TIdPID = LongWord;
  455. TIdThreadId = LongWord;
  456. TIdThreadHandle = System.Threading.Thread;
  457. {$IFDEF DOTNETDISTRO}
  458. TIdThreadPriority = System.Threading.ThreadPriority;
  459. {$ELSE}
  460. TIdThreadPriority = TThreadPriority;
  461. {$ENDIF}
  462. {$ENDIF}
  463. {$IFDEF UNIX}
  464. {$IFDEF KYLIXCOMPAT}
  465. TIdPID = LongInt;
  466. TIdThreadId = LongInt;
  467. {$IFDEF FPC}
  468. TIdThreadHandle = TThreadID;
  469. {$ELSE}
  470. TIdThreadHandle = Cardinal;
  471. {$ENDIF}
  472. {$IFDEF INT_THREAD_PRIORITY}
  473. TIdThreadPriority = -20..19;
  474. {$ELSE}
  475. TIdThreadPriority = TThreadPriority;
  476. {$ENDIF}
  477. {$ENDIF}
  478. {$IFDEF USE_BASEUNIX}
  479. TIdPID = TPid;
  480. TIdThreadId = TThreadId;
  481. TIdThreadHandle = TIdThreadId;
  482. TIdThreadPriority = TThreadPriority;
  483. {$ENDIF}
  484. {$IFDEF USE_VCL_POSIX}
  485. TIdPID = pid_t;
  486. TIdThreadId = NativeUInt;
  487. TIdThreadHandle = NativeUInt;
  488. {$IFDEF INT_THREAD_PRIORITY}
  489. TIdThreadPriority = -20..19;
  490. {$ELSE}
  491. TIdThreadPriority = TThreadPriority;
  492. {$ENDIF}
  493. {$ENDIF}
  494. {$ENDIF}
  495. {$IFDEF WINDOWS}
  496. TIdPID = LongWord;
  497. TIdThreadId = LongWord;
  498. TIdThreadHandle = THandle;
  499. TIdThreadPriority = TThreadPriority;
  500. {$ENDIF}
  501. {$IFDEF INT_THREAD_PRIORITY}
  502. const
  503. // approximate values, its finer grained on Linux
  504. tpIdle = 19;
  505. tpLowest = 12;
  506. tpLower = 6;
  507. tpNormal = 0;
  508. tpHigher = -7;
  509. tpHighest = -13;
  510. tpTimeCritical = -20;
  511. {$ENDIF}
  512. {CH tpIdLowest = tpLowest; }
  513. {CH tpIdBelowNormal = tpLower; }
  514. {CH tpIdNormal = tpNormal; }
  515. {CH tpIdAboveNormal = tpHigher; }
  516. {CH tpIdHighest = tpHighest; }
  517. //end thread stuff
  518. const
  519. //leave this as zero. It's significant in many socket calls that specify ports
  520. DEF_PORT_ANY = 0;
  521. type
  522. {$IFDEF DOTNET}
  523. TIdUnicodeString = System.String;
  524. {$ELSE}
  525. {$IFDEF HAS_UnicodeString}
  526. TIdUnicodeString = UnicodeString;
  527. {$ELSE}
  528. TIdUnicodeString = WideString;
  529. {$ENDIF}
  530. {$ENDIF}
  531. {$IFDEF STRING_IS_UNICODE}
  532. TIdWideChar = Char;
  533. PIdWideChar = PChar;
  534. {$ELSE}
  535. TIdWideChar = WideChar;
  536. PIdWideChar = PWideChar;
  537. {$ENDIF}
  538. {$IFDEF HAS_TBytes}
  539. TIdBytes = TBytes;
  540. {$ELSE}
  541. TIdBytes = array of Byte;
  542. {$ENDIF}
  543. {$IFDEF HAS_WIDE_TCharArray}
  544. TIdWideChars = TCharArray;
  545. {$ELSE}
  546. TIdWideChars = array of TIdWideChar;
  547. {$ENDIF}
  548. //NOTE: The code below assumes a 32bit Linux architecture (such as target i386-linux)
  549. {$UNDEF CPU32_OR_KYLIX}
  550. {$IFNDEF DOTNET}
  551. {$IFDEF CPU32}
  552. {$DEFINE CPU32_OR_KYLIX}
  553. {$ENDIF}
  554. {$IFDEF KYLIX}
  555. {$DEFINE CPU32_OR_KYLIX}
  556. {$ENDIF}
  557. {$ENDIF}
  558. // native signed and unsigned integer sized pointer types
  559. {$IFDEF DOTNET}
  560. TIdNativeInt = IntPtr;
  561. TIdNativeUInt = UIntPtr;
  562. {$ELSE}
  563. {$UNDEF HAS_NATIVEINT}
  564. {$UNDEF HAS_NATIVEUINT}
  565. {$IFDEF HAS_NativeInt}
  566. TIdNativeInt = NativeInt;
  567. {$ELSE}
  568. {$IFDEF CPU32}
  569. TIdNativeInt = LongInt;
  570. {$ENDIF}
  571. {$IFDEF CPU64}
  572. TIdNativeInt = Int64;
  573. {$ENDIF}
  574. {$ENDIF}
  575. {$IFDEF HAS_NativeUInt}
  576. TIdNativeUInt = NativeUInt;
  577. {$ELSE}
  578. {$IFDEF CPU32}
  579. TIdNativeUInt = LongWord;
  580. {$ENDIF}
  581. {$IFDEF CPU64}
  582. {$IFDEF HAS_UInt64}
  583. TIdNativeUInt = UInt64;
  584. {$ELSE}
  585. TIdNativeUInt = Int64;
  586. {$ENDIF}
  587. {$ENDIF}
  588. {$ENDIF}
  589. {$ENDIF}
  590. {$IFNDEF HAS_PtrInt}
  591. PtrInt = TIdNativeInt;
  592. {$ENDIF}
  593. {$IFNDEF HAS_PtrUInt}
  594. PtrUInt = TIdNativeUInt;
  595. {$ENDIF}
  596. {$IFDEF STREAM_SIZE_64}
  597. TIdStreamSize = Int64;
  598. {$ELSE}
  599. TIdStreamSize = Integer;
  600. {$ENDIF}
  601. {$IFNDEF HAS_SIZE_T}
  602. {$EXTERNALSYM size_t}
  603. size_t = PtrUInt;
  604. {$ENDIF}
  605. {
  606. Delphi/C++Builder 2009+ have a TEncoding class which mirrors System.Text.Encoding
  607. in .NET, but does not have a TDecoder class which mirrors System.Text.Decoder
  608. in .NET. For earlier versions, or when the libiconv library is enabled,
  609. TIdTextEncoding is a wrapper class, otherwise it maps directly to the OS/RTL's
  610. encoding class.
  611. This way, Indy can have a unified internal interface for String<->Byte conversions
  612. without using IFDEFs everywhere.
  613. Note: Having the wrapper class use WideString in earlier versions adds extra
  614. overhead to string operations, but this is the only way to ensure that strings
  615. are encoded properly. Later on, perhaps we can optimize the operations when
  616. Ansi-compatible encodings are being used with AnsiString values.
  617. }
  618. {$UNDEF TIdASCIIEncoding_NEEDED}
  619. {$IFDEF TIdTextEncoding_IS_NATIVE}
  620. {$IFDEF DOTNET}
  621. TIdTextEncoding = System.Text.Encoding;
  622. //TIdMBCSEncoding = ?
  623. TIdASCIIEncoding = System.Text.ASCIIEncoding;
  624. TIdUTF7Encoding = System.Text.UTF7Encoding;
  625. TIdUTF8Encoding = System.Text.UTF8Encoding;
  626. TIdUTF16LittleEndianEncoding = System.Text.UnicodeEncoding;
  627. TIdUTF16BigEndianEncoding = System.Text.UnicodeEncoding;
  628. {$ELSE}
  629. TIdTextEncoding = SysUtils.TEncoding;
  630. TIdMBCSEncoding = SysUtils.TMBCSEncoding;
  631. {$DEFINE TIdASCIIEncoding_NEEDED} // see further below
  632. TIdUTF7Encoding = SysUtils.TUTF7Encoding;
  633. TIdUTF8Encoding = SysUtils.TUTF8Encoding;
  634. TIdUTF16LittleEndianEncoding = SysUtils.TUnicodeEncoding;
  635. TIdUTF16BigEndianEncoding = SysUtils.TBigEndianUnicodeEncoding;
  636. {$ENDIF}
  637. {$ELSE}
  638. TIdTextEncoding = class
  639. {$IFDEF HAS_CLASSPROPERTIES}
  640. private
  641. class function GetASCII: TIdTextEncoding; static;
  642. class function GetBigEndianUnicode: TIdTextEncoding; static;
  643. class function GetDefault: TIdTextEncoding; static;
  644. class function GetUnicode: TIdTextEncoding; static;
  645. class function GetUTF7: TIdTextEncoding; static;
  646. class function GetUTF8: TIdTextEncoding; static;
  647. {$ENDIF}
  648. protected
  649. FIsSingleByte: Boolean;
  650. FMaxCharSize: Integer;
  651. function GetByteCount(AChars: PIdWideChar; ACharCount: Integer): Integer; overload; virtual; abstract;
  652. function GetBytes(AChars: PIdWideChar; ACharCount: Integer; ABytes: PByte; AByteCount: Integer): Integer; overload; virtual; abstract;
  653. function GetCharCount(ABytes: PByte; AByteCount: Integer): Integer; overload; virtual; abstract;
  654. function GetChars(ABytes: PByte; AByteCount: Integer; AChars: PIdWideChar; ACharCount: Integer): Integer; overload; virtual; abstract;
  655. public
  656. class function Convert(ASource, ADestination: TIdTextEncoding; const ABytes: TIdBytes): TIdBytes; overload;
  657. class function Convert(ASource, ADestination: TIdTextEncoding; const ABytes: TIdBytes; AStartIndex, ACount: Integer): TIdBytes; overload;
  658. class procedure FreeEncodings;
  659. class function IsStandardEncoding(AEncoding: TIdTextEncoding): Boolean;
  660. class function GetBufferEncoding(const ABuffer: TIdBytes; var AEncoding: TIdTextEncoding): Integer;
  661. function GetByteCount(const AChars: TIdWideChars): Integer; overload;
  662. function GetByteCount(const AChars: TIdWideChars; ACharIndex, ACharCount: Integer): Integer; overload;
  663. function GetByteCount(const AStr: TIdUnicodeString): Integer; overload;
  664. function GetByteCount(const AStr: TIdUnicodeString; ACharIndex, ACharCount: Integer): Integer; overload;
  665. function GetBytes(const AChars: TIdWideChars): TIdBytes; overload;
  666. function GetBytes(const AChars: TIdWideChars; ACharIndex, ACharCount: Integer; var VBytes: TIdBytes; AByteIndex: Integer): Integer; overload;
  667. function GetBytes(const AStr: TIdUnicodeString): TIdBytes; overload;
  668. function GetBytes(const AStr: TIdUnicodeString; ACharIndex, ACharCount: Integer; var VBytes: TIdBytes; AByteIndex: Integer): Integer; overload;
  669. function GetCharCount(const ABytes: TIdBytes): Integer; overload;
  670. function GetCharCount(const ABytes: TIdBytes; AByteIndex, AByteCount: Integer): Integer; overload;
  671. function GetChars(const ABytes: TIdBytes): TIdWideChars; overload;
  672. function GetChars(const ABytes: TIdBytes; AByteIndex, AByteCount: Integer): TIdWideChars; overload;
  673. function GetChars(const ABytes: TIdBytes; AByteIndex, AByteCount: Integer; var VChars: TIdWideChars; ACharIndex: Integer): Integer; overload;
  674. {$IFDEF USE_ICONV}
  675. class function GetEncoding(const ACharSet: String): TIdTextEncoding;
  676. {$ELSE}
  677. {$IFDEF WINDOWS}
  678. class function GetEncoding(ACodePage: Integer): TIdTextEncoding;
  679. {$ENDIF}
  680. {$ENDIF}
  681. function GetMaxByteCount(ACharCount: Integer): Integer; virtual; abstract;
  682. function GetMaxCharCount(AByteCount: Integer): Integer; virtual; abstract;
  683. function GetPreamble: TIdBytes; virtual; abstract;
  684. function GetString(const ABytes: TIdBytes): TIdUnicodeString; overload;
  685. function GetString(const ABytes: TIdBytes; AByteIndex, AByteCount: Integer): TIdUnicodeString; overload;
  686. {$IFDEF HAS_CLASSPROPERTIES}
  687. class property ASCII: TIdTextEncoding read GetASCII;
  688. class property BigEndianUnicode: TIdTextEncoding read GetBigEndianUnicode;
  689. class property Default: TIdTextEncoding read GetDefault;
  690. {$ELSE}
  691. class function ASCII: TIdTextEncoding;
  692. class function BigEndianUnicode: TIdTextEncoding;
  693. class function Default: TIdTextEncoding;
  694. {$ENDIF}
  695. property IsSingleByte: Boolean read FIsSingleByte;
  696. {$IFDEF HAS_CLASSPROPERTIES}
  697. class property Unicode: TIdTextEncoding read GetUnicode;
  698. class property UTF7: TIdTextEncoding read GetUTF7;
  699. class property UTF8: TIdTextEncoding read GetUTF8;
  700. {$ELSE}
  701. class function Unicode: TIdTextEncoding;
  702. class function UTF7: TIdTextEncoding;
  703. class function UTF8: TIdTextEncoding;
  704. {$ENDIF}
  705. end;
  706. TIdMBCSEncoding = class(TIdTextEncoding)
  707. private
  708. {$IFDEF USE_ICONV}
  709. FCharSet: AnsiString;
  710. FToUTF16 : iconv_t;
  711. FFromUTF16 : iconv_t;
  712. {$ELSE}
  713. {$IFDEF WINDOWS}
  714. FCodePage: Cardinal;
  715. FMBToWCharFlags: Cardinal;
  716. FWCharToMBFlags: Cardinal;
  717. {$ENDIF}
  718. {$ENDIF}
  719. protected
  720. function GetByteCount(Chars: PWideChar; CharCount: Integer): Integer; overload; override;
  721. function GetBytes(Chars: PWideChar; CharCount: Integer; Bytes: PByte; ByteCount: Integer): Integer; overload; override;
  722. function GetCharCount(Bytes: PByte; ByteCount: Integer): Integer; overload; override;
  723. function GetChars(Bytes: PByte; ByteCount: Integer; Chars: PWideChar; CharCount: Integer): Integer; overload; override;
  724. public
  725. constructor Create; overload; virtual;
  726. {$IFDEF USE_ICONV}
  727. constructor Create(const CharSet : AnsiString); overload; virtual;
  728. destructor Destroy; override;
  729. {$ELSE}
  730. {$IFDEF WINDOWS}
  731. constructor Create(CodePage: Integer); overload; virtual;
  732. constructor Create(CodePage, MBToWCharFlags, WCharToMBFlags: Integer); overload; virtual;
  733. {$ENDIF}
  734. {$ENDIF}
  735. function GetMaxByteCount(CharCount: Integer): Integer; override;
  736. function GetMaxCharCount(ByteCount: Integer): Integer; override;
  737. function GetPreamble: TIdBytes; override;
  738. end;
  739. {$DEFINE TIdASCIIEncoding_NEEDED} // see further below
  740. TIdUTF7Encoding = class(TIdMBCSEncoding)
  741. protected
  742. function GetByteCount(Chars: PWideChar; CharCount: Integer): Integer; overload; override;
  743. function GetBytes(Chars: PWideChar; CharCount: Integer; Bytes: PByte; ByteCount: Integer): Integer; overload; override;
  744. function GetCharCount(Bytes: PByte; ByteCount: Integer): Integer; overload; override;
  745. function GetChars(Bytes: PByte; ByteCount: Integer; Chars: PWideChar; CharCount: Integer): Integer; overload; override;
  746. public
  747. constructor Create; override;
  748. function GetMaxByteCount(CharCount: Integer): Integer; override;
  749. function GetMaxCharCount(ByteCount: Integer): Integer; override;
  750. end;
  751. TIdUTF8Encoding = class(TIdUTF7Encoding)
  752. public
  753. constructor Create; override;
  754. function GetMaxByteCount(CharCount: Integer): Integer; override;
  755. function GetMaxCharCount(ByteCount: Integer): Integer; override;
  756. function GetPreamble: TIdBytes; override;
  757. end;
  758. TIdUTF16LittleEndianEncoding = class(TIdTextEncoding)
  759. protected
  760. function GetByteCount(Chars: PWideChar; CharCount: Integer): Integer; overload; override;
  761. function GetBytes(Chars: PWideChar; CharCount: Integer; Bytes: PByte; ByteCount: Integer): Integer; overload; override;
  762. function GetCharCount(Bytes: PByte; ByteCount: Integer): Integer; overload; override;
  763. function GetChars(Bytes: PByte; ByteCount: Integer; Chars: PWideChar; CharCount: Integer): Integer; overload; override;
  764. public
  765. constructor Create; virtual;
  766. function GetMaxByteCount(CharCount: Integer): Integer; override;
  767. function GetMaxCharCount(ByteCount: Integer): Integer; override;
  768. function GetPreamble: TIdBytes; override;
  769. end;
  770. TIdUTF16BigEndianEncoding = class(TIdUTF16LittleEndianEncoding)
  771. protected
  772. function GetBytes(Chars: PWideChar; CharCount: Integer; Bytes: PByte; ByteCount: Integer): Integer; overload; override;
  773. function GetChars(Bytes: PByte; ByteCount: Integer; Chars: PWideChar; CharCount: Integer): Integer; overload; override;
  774. public
  775. function GetPreamble: TIdBytes; override;
  776. end;
  777. {$ENDIF}
  778. {$IFDEF TIdASCIIEncoding_NEEDED}
  779. TIdASCIIEncoding = class(TIdTextEncoding)
  780. protected
  781. function GetByteCount(AChars: PIdWideChar; ACharCount: Integer): Integer; override;
  782. function GetBytes(AChars: PIdWideChar; ACharCount: Integer; ABytes: PByte; AByteCount: Integer): Integer; override;
  783. function GetCharCount(ABytes: PByte; AByteCount: Integer): Integer; override;
  784. function GetChars(ABytes: PByte; AByteCount: Integer; AChars: PIdWideChar; ACharCount: Integer): Integer; override;
  785. public
  786. constructor Create; virtual;
  787. function GetMaxByteCount(ACharCount: Integer): Integer; override;
  788. function GetMaxCharCount(AByteCount: Integer): Integer; override;
  789. function GetPreamble: TIdBytes; override;
  790. end;
  791. {$ENDIF}
  792. // These are for backwards compatibility with past Indy 10 releases
  793. function enDefault: TIdTextEncoding; {$IFDEF HAS_DEPRECATED}deprecated{$IFDEF HAS_DEPRECATED_MSG} 'Use a nil TIdTextEncoding pointer'{$ENDIF};{$ENDIF}
  794. {$NODEFINE enDefault}
  795. function en7Bit: TIdTextEncoding; {$IFDEF HAS_DEPRECATED}deprecated{$IFDEF HAS_DEPRECATED_MSG} 'Use IndyASCIIEncoding()'{$ENDIF};{$ENDIF}
  796. {$NODEFINE en7Bit}
  797. function en8Bit: TIdTextEncoding; {$IFDEF HAS_DEPRECATED}deprecated{$IFDEF HAS_DEPRECATED_MSG} 'Use Indy8BitEncoding()'{$ENDIF};{$ENDIF}
  798. {$NODEFINE en8Bit}
  799. function enUTF8: TIdTextEncoding; {$IFDEF HAS_DEPRECATED}deprecated{$IFDEF HAS_DEPRECATED_MSG} 'Use IndyUTF8Encoding()'{$ENDIF};{$ENDIF}
  800. {$NODEFINE enUTF8}
  801. function Indy8BitEncoding{$IFNDEF DOTNET}(const AOwnedByIndy: Boolean = True){$ENDIF}: TIdTextEncoding;
  802. function IndyASCIIEncoding{$IFNDEF DOTNET}(const AOwnedByIndy: Boolean = True){$ENDIF}: TIdTextEncoding;
  803. function IndyUTF8Encoding{$IFNDEF DOTNET}(const AOwnedByIndy: Boolean = True){$ENDIF}: TIdTextEncoding;
  804. (*$HPPEMIT '// These are helper macros to handle differences in "class" properties between different C++Builder versions'*)
  805. {$IFDEF HAS_CLASSPROPERTIES}
  806. (*$HPPEMIT '#define TIdTextEncoding_ASCII TIdTextEncoding::ASCII'*)
  807. (*$HPPEMIT '#define TIdTextEncoding_BigEndianUnicode TIdTextEncoding::BigEndianUnicode'*)
  808. (*$HPPEMIT '#define TIdTextEncoding_Default TIdTextEncoding::Default'*)
  809. (*$HPPEMIT '#define TIdTextEncoding_Unicode TIdTextEncoding::Unicode'*)
  810. (*$HPPEMIT '#define TIdTextEncoding_UTF7 TIdTextEncoding::UTF7'*)
  811. (*$HPPEMIT '#define TIdTextEncoding_UTF8 TIdTextEncoding::UTF8'*)
  812. {$ELSE}
  813. (*$HPPEMIT '#define TIdTextEncoding_ASCII TIdTextEncoding::ASCII(__classid(TIdTextEncoding))'*)
  814. (*$HPPEMIT '#define TIdTextEncoding_BigEndianUnicode TIdTextEncoding::BigEndianUnicode(__classid(TIdTextEncoding))'*)
  815. (*$HPPEMIT '#define TIdTextEncoding_Default TIdTextEncoding::Default(__classid(TIdTextEncoding))'*)
  816. (*$HPPEMIT '#define TIdTextEncoding_Unicode TIdTextEncoding::Unicode(__classid(TIdTextEncoding))'*)
  817. (*$HPPEMIT '#define TIdTextEncoding_UTF7 TIdTextEncoding::UTF7(__classid(TIdTextEncoding))'*)
  818. (*$HPPEMIT '#define TIdTextEncoding_UTF8 TIdTextEncoding::UTF8(__classid(TIdTextEncoding))'*)
  819. {$ENDIF}
  820. (*$HPPEMIT ''*)
  821. (*$HPPEMIT '// These are for backwards compatibility with earlier Indy 10 releases'*)
  822. (*$HPPEMIT '#define enDefault ( ( TIdTextEncoding* )NULL )'*)
  823. {$IFDEF DOTNET}
  824. (*$HPPEMIT '#define en8Bit Indy8BitEncoding()'*)
  825. (*$HPPEMIT '#define en7Bit IndyASCIIEncoding()'*)
  826. (*$HPPEMIT '#define enUTF8 IndyUTF8Encoding()'*)
  827. {$ELSE}
  828. (*$HPPEMIT '#define en8Bit Indy8BitEncoding(true)'*)
  829. (*$HPPEMIT '#define en7Bit IndyASCIIEncoding(true)'*)
  830. (*$HPPEMIT '#define enUTF8 IndyUTF8Encoding(true)'*)
  831. {$ENDIF}
  832. (*$HPPEMIT ''*)
  833. type
  834. IdAnsiEncodingType = (encIndyDefault, encOSDefault, encASCII, encUTF7, encUTF8, enc8Bit);
  835. var
  836. {RLebeau: using ASCII by default because most Internet protocols that Indy
  837. implements are based on ASCII specifically, not Ansi. Non-ASCII data has
  838. to be explicitally allowed by RFCs, in which case the caller should not be
  839. using nil TIdTextEncoding objects to begin with...}
  840. GIdDefaultAnsiEncoding: IdAnsiEncodingType = encASCII;
  841. procedure EnsureEncoding(var VEncoding : TIdTextEncoding; ADefEncoding: IdAnsiEncodingType = encIndyDefault);
  842. type
  843. TIdAppendFileStream = class(TFileStream)
  844. public
  845. constructor Create(const AFile : String);
  846. end;
  847. TIdReadFileExclusiveStream = class(TFileStream)
  848. public
  849. constructor Create(const AFile : String);
  850. end;
  851. TIdReadFileNonExclusiveStream = class(TFileStream)
  852. public
  853. constructor Create(const AFile : String);
  854. end;
  855. TIdFileCreateStream = class(TFileStream)
  856. public
  857. constructor Create(const AFile : String);
  858. end;
  859. {$IFDEF DOTNET}
  860. {$IFNDEF DOTNET_2_OR_ABOVE}
  861. // dotNET implementation
  862. TWaitResult = (wrSignaled, wrTimeout, wrAbandoned, wrError);
  863. TEvent = class(TObject)
  864. protected
  865. FEvent: WaitHandle;
  866. public
  867. constructor Create(EventAttributes: IntPtr; ManualReset,
  868. InitialState: Boolean; const Name: string = ''); overload;
  869. constructor Create; overload;
  870. destructor Destroy; override;
  871. procedure SetEvent;
  872. procedure ResetEvent;
  873. function WaitFor(Timeout: LongWord): TWaitResult; virtual;
  874. end;
  875. TCriticalSection = class(TObject)
  876. public
  877. procedure Acquire; virtual;
  878. procedure Release; virtual;
  879. function TryEnter: Boolean;
  880. procedure Enter;
  881. procedure Leave;
  882. end;
  883. {$ENDIF}
  884. {$ELSE}
  885. {$IFNDEF NO_REDECLARE}
  886. // TCriticalSection = SyncObjs.TCriticalSection;
  887. {$ENDIF}
  888. {$ENDIF}
  889. TIdLocalEvent = class(TEvent)
  890. public
  891. constructor Create(const AInitialState: Boolean = False;
  892. const AManualReset: Boolean = False); reintroduce;
  893. function WaitForEver: TWaitResult; overload;
  894. end;
  895. // This is here to reduce all the warnings about imports. We may also ifdef
  896. // it to provide a non warning implementatino on this unit too later.
  897. TIdCriticalSection = class(TCriticalSection)
  898. end;
  899. {$IFDEF DOTNET}
  900. Short = System.Int16;
  901. {$ENDIF}
  902. {$IFDEF UNIX}
  903. Short = Smallint; //Only needed for ToBytes(Short) and BytesToShort
  904. {$ENDIF}
  905. {$IFNDEF DOTNET}
  906. {$IFNDEF NO_REDECLARE}
  907. PShort = ^Short;
  908. {$ENDIF}
  909. {$ENDIF}
  910. {$IFNDEF DOTNET}
  911. {$IFNDEF HAS_PCardinal}
  912. PCardinal = ^Cardinal;
  913. {$ENDIF}
  914. {$ENDIF}
  915. //This usually is a property editor exception
  916. EIdCorruptServicesFile = class(EIdException);
  917. EIdEndOfStream = class(EIdException);
  918. EIdInvalidIPv6Address = class(EIdException);
  919. EIdNoEncodingSpecified = class(EIdException);
  920. //This is called whenever there is a failure to retreive the time zone information
  921. EIdFailedToRetreiveTimeZoneInfo = class(EIdException);
  922. TIdPort = Word;
  923. //We don't have a native type that can hold an IPv6 address.
  924. {$NODEFINE TIdIPv6Address}
  925. TIdIPv6Address = array [0..7] of word;
  926. // C++ does not allow an array to be returned by a function,
  927. // so wrapping the array in a struct as a workaround...
  928. (*$HPPEMIT 'namespace Idglobal'*)
  929. (*$HPPEMIT '{'*)
  930. (*$HPPEMIT ' struct TIdIPv6Address'*)
  931. (*$HPPEMIT ' {'*)
  932. (*$HPPEMIT ' ::System::Word data[8];'*)
  933. (*$HPPEMIT ' ::System::Word& operator[](int index) { return data[index]; }'*)
  934. (*$HPPEMIT ' const ::System::Word& operator[](int index) const { return data[index]; }'*)
  935. (*$HPPEMIT ' operator const ::System::Word*() const { return data; }'*)
  936. (*$HPPEMIT ' operator ::System::Word*() { return data; }'*)
  937. (*$HPPEMIT ' };'*)
  938. (*$HPPEMIT '}'*)
  939. {This way instead of a boolean for future expansion of other actions}
  940. TIdMaxLineAction = (maException, maSplit);
  941. TIdOSType = (otUnknown, otUnix, otWindows, otDotNet);
  942. //This is for IPv6 support when merged into the core
  943. TIdIPVersion = (Id_IPv4, Id_IPv6);
  944. {$IFNDEF NO_REDECLARE}
  945. {$IFDEF LINUX}
  946. {$IFNDEF VCL_6_OR_ABOVE}
  947. THandle = LongWord; //D6.System
  948. {$ENDIF}
  949. {$ENDIF}
  950. {$ENDIF}
  951. {$IFDEF DOTNET}
  952. THandle = Integer;
  953. {$ELSE}
  954. {$IFDEF WINDOWS}
  955. // THandle = Windows.THandle;
  956. {$ENDIF}
  957. {$ENDIF}
  958. TPosProc = function(const substr, str: String): LongInt;
  959. {$IFNDEF DOTNET}
  960. TStrScanProc = function(Str: PChar; Chr: Char): PChar;
  961. {$ENDIF}
  962. TIdReuseSocket = (rsOSDependent, rsTrue, rsFalse);
  963. {$IFNDEF HAS_TList_Assign}
  964. TIdExtList = class(TList) // We use this hack-class, because TList has no .assign on Delphi 5.
  965. public // Do NOT add DataMembers to this class !!!
  966. procedure Assign(AList: TList);
  967. end;
  968. {$ELSE}
  969. TIdExtList = class(TList);
  970. {$ENDIF}
  971. {$IFNDEF STREAM_SIZE_64}
  972. type
  973. TSeekOrigin = (soBeginning, soCurrent, soEnd);
  974. {$ENDIF}
  975. // TIdBaseStream is defined here to allow TIdMultiPartFormData to be defined
  976. // without any $IFDEFs in the unit IdMultiPartFormData - in accordance with Indy Coding rules
  977. TIdBaseStream = class(TStream)
  978. protected
  979. function IdRead(var VBuffer: TIdBytes; AOffset, ACount: Longint): Longint; virtual; abstract;
  980. function IdWrite(const ABuffer: TIdBytes; AOffset, ACount: Longint): Longint; virtual; abstract;
  981. function IdSeek(const AOffset: Int64; AOrigin: TSeekOrigin): Int64; virtual; abstract;
  982. procedure IdSetSize(ASize: Int64); virtual; abstract;
  983. {$IFDEF DOTNET}
  984. procedure SetSize(ASize: Int64); override;
  985. {$ELSE}
  986. {$IFDEF STREAM_SIZE_64}
  987. procedure SetSize(const NewSize: Int64); override;
  988. {$ELSE}
  989. procedure SetSize(ASize: Integer); override;
  990. {$ENDIF}
  991. {$ENDIF}
  992. public
  993. {$IFDEF DOTNET}
  994. function Read(var VBuffer: array of Byte; AOffset, ACount: Longint): Longint; override;
  995. function Write(const ABuffer: array of Byte; AOffset, ACount: Longint): Longint; override;
  996. function Seek(const AOffset: Int64; AOrigin: TSeekOrigin): Int64; override;
  997. {$ELSE}
  998. function Read(var Buffer; Count: Longint): Longint; override;
  999. function Write(const Buffer; Count: Longint): Longint; override;
  1000. {$IFDEF STREAM_SIZE_64}
  1001. function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override;
  1002. {$ELSE}
  1003. function Seek(Offset: Longint; Origin: Word): Longint; override;
  1004. {$ENDIF}
  1005. {$ENDIF}
  1006. end;
  1007. TIdStreamReadEvent = procedure(var VBuffer: TIdBytes; AOffset, ACount: Longint; var VResult: Longint) of object;
  1008. TIdStreamWriteEvent = procedure(const ABuffer: TIdBytes; AOffset, ACount: Longint; var VResult: Longint) of object;
  1009. TIdStreamSeekEvent = procedure(const AOffset: Int64; AOrigin: TSeekOrigin; var VPosition: Int64) of object;
  1010. TIdStreamSetSizeEvent = procedure(const ANewSize: Int64) of object;
  1011. TIdEventStream = class(TIdBaseStream)
  1012. protected
  1013. FOnRead: TIdStreamReadEvent;
  1014. FOnWrite: TIdStreamWriteEvent;
  1015. FOnSeek: TIdStreamSeekEvent;
  1016. FOnSetSize: TIdStreamSetSizeEvent;
  1017. function IdRead(var VBuffer: TIdBytes; AOffset, ACount: Longint): Longint; override;
  1018. function IdWrite(const ABuffer: TIdBytes; AOffset, ACount: Longint): Longint; override;
  1019. function IdSeek(const AOffset: Int64; AOrigin: TSeekOrigin): Int64; override;
  1020. procedure IdSetSize(ASize: Int64); override;
  1021. public
  1022. property OnRead: TIdStreamReadEvent read FOnRead write FOnRead;
  1023. property OnWrite: TIdStreamWriteEvent read FOnWrite write FOnWrite;
  1024. property OnSeek: TIdStreamSeekEvent read FOnSeek write FOnSeek;
  1025. property OnSetSize: TIdStreamSetSizeEvent read FOnSetSize write FOnSetSize;
  1026. end;
  1027. {$IFNDEF DOTNET} // what is the .NET equivilent?
  1028. TIdMemoryBufferStream = class(TCustomMemoryStream)
  1029. public
  1030. constructor Create(APtr: Pointer; ASize: TIdNativeInt);
  1031. function Write(const Buffer; Count: Longint): Longint; override;
  1032. end;
  1033. {$ENDIF}
  1034. const
  1035. {$IFDEF UNIX}
  1036. GOSType = otUnix;
  1037. GPathDelim = '/'; {do not localize}
  1038. INFINITE = LongWord($FFFFFFFF); { Infinite timeout }
  1039. {$ENDIF}
  1040. {$IFDEF WINDOWS}
  1041. GOSType = otWindows;
  1042. GPathDelim = '\'; {do not localize}
  1043. Infinite = Windows.INFINITE; { redeclare here for use elsewhere without using Windows.pas } // cls modified 1/23/2002
  1044. {$ENDIF}
  1045. {$IFDEF DOTNET}
  1046. GOSType = otDotNet;
  1047. GPathDelim = '\'; {do not localize}
  1048. // Infinite = ?; { redeclare here for use elsewhere without using Windows.pas } // cls modified 1/23/2002
  1049. {$ENDIF}
  1050. // S.G. 4/9/2002: IP version general switch for defaults
  1051. {$IFDEF IdIPv6}
  1052. ID_DEFAULT_IP_VERSION = Id_IPv6;
  1053. {$ELSE}
  1054. ID_DEFAULT_IP_VERSION = Id_IPv4;
  1055. {$ENDIF}
  1056. {$IFNDEF HAS_sLineBreak}
  1057. {$IFDEF WINDOWS}
  1058. sLineBreak = CR + LF;
  1059. {$ELSE}
  1060. sLineBreak = LF;
  1061. {$ENDIF}
  1062. {$ENDIF}
  1063. //The power constants are for processing IP addresses
  1064. //They are powers of 255.
  1065. const
  1066. POWER_1 = $000000FF;
  1067. POWER_2 = $0000FFFF;
  1068. POWER_3 = $00FFFFFF;
  1069. POWER_4 = $FFFFFFFF;
  1070. // utility functions to calculate the usable length of a given buffer.
  1071. // If ALength is <0 then the actual Buffer length is returned,
  1072. // otherwise the minimum of the two lengths is returned instead.
  1073. function IndyLength(const ABuffer: String; const ALength: Integer = -1; const AIndex: Integer = 1): Integer; overload;
  1074. function IndyLength(const ABuffer: TIdBytes; const ALength: Integer = -1; const AIndex: Integer = 0): Integer; overload;
  1075. function IndyLength(const ABuffer: TStream; const ALength: TIdStreamSize = -1): TIdStreamSize; overload;
  1076. function IndyFormat(const AFormat: string; const Args: array of const): string;
  1077. function IndyIncludeTrailingPathDelimiter(const S: string): string;
  1078. function IndyExcludeTrailingPathDelimiter(const S: string): string;
  1079. procedure IndyRaiseLastError;
  1080. //You could possibly use the standard StrInt and StrIntDef but these
  1081. //also remove spaces from the string using the trim functions.
  1082. function IndyStrToInt(const S: string): Integer; overload;
  1083. function IndyStrToInt(const S: string; ADefault: Integer): Integer; overload;
  1084. function IndyFileAge(const AFileName: string): TDateTime;
  1085. function IndyDirectoryExists(const ADirectory: string): Boolean;
  1086. //You could possibly use the standard StrToInt and StrToInt64Def
  1087. //functions but these also remove spaces using the trim function
  1088. function IndyStrToInt64(const S: string; const ADefault: Int64): Int64; overload;
  1089. function IndyStrToInt64(const S: string): Int64; overload;
  1090. //This converts the string to an Integer or Int64 depending on the bit size TStream uses
  1091. function IndyStrToStreamSize(const S: string; const ADefault: TIdStreamSize): TIdStreamSize; overload;
  1092. function IndyStrToStreamSize(const S: string): TIdStreamSize; overload;
  1093. function AddMSecToTime(const ADateTime: TDateTime; const AMSec: Integer): TDateTime;
  1094. // To and From Bytes conversion routines
  1095. function ToBytes(const AValue: string; ADestEncoding: TIdTextEncoding = nil
  1096. {$IFDEF STRING_IS_ANSI}; ASrcEncoding: TIdTextEncoding = nil{$ENDIF}
  1097. ): TIdBytes; overload;
  1098. function ToBytes(const AValue: string; const ALength: Integer; const AIndex: Integer = 1;
  1099. ADestEncoding: TIdTextEncoding = nil
  1100. {$IFDEF STRING_IS_ANSI}; ASrcEncoding: TIdTextEncoding = nil{$ENDIF}
  1101. ): TIdBytes; overload;
  1102. function ToBytes(const AValue: Char; ADestEncoding: TIdTextEncoding = nil
  1103. {$IFDEF STRING_IS_ANSI}; ASrcEncoding: TIdTextEncoding = nil{$ENDIF}
  1104. ): TIdBytes; overload;
  1105. function ToBytes(const AValue: LongInt): TIdBytes; overload;
  1106. function ToBytes(const AValue: Short): TIdBytes; overload;
  1107. function ToBytes(const AValue: Word): TIdBytes; overload;
  1108. function ToBytes(const AValue: Byte): TIdBytes; overload;
  1109. function ToBytes(const AValue: LongWord): TIdBytes; overload;
  1110. function ToBytes(const AValue: Int64): TIdBytes; overload;
  1111. function ToBytes(const AValue: TIdBytes; const ASize: Integer; const AIndex: Integer = 0): TIdBytes; overload;
  1112. {$IFNDEF DOTNET}
  1113. // RLebeau - not using the same "ToBytes" naming convention for RawToBytes()
  1114. // in order to prevent ambiquious errors with ToBytes(TIdBytes) above
  1115. function RawToBytes(const AValue; const ASize: Integer): TIdBytes;
  1116. {$ENDIF}
  1117. // The following functions are faster but except that Bytes[] must have enough
  1118. // space for at least SizeOf(AValue) bytes.
  1119. procedure ToBytesF(var Bytes: TIdBytes; const AValue: Char; ADestEncoding: TIdTextEncoding = nil
  1120. {$IFDEF STRING_IS_ANSI}; ASrcEncoding: TIdTextEncoding = nil{$ENDIF}
  1121. ); overload;
  1122. procedure ToBytesF(var Bytes: TIdBytes; const AValue: LongInt); overload;
  1123. procedure ToBytesF(var Bytes: TIdBytes; const AValue: Short); overload;
  1124. procedure ToBytesF(var Bytes: TIdBytes; const AValue: Word); overload;
  1125. procedure ToBytesF(var Bytes: TIdBytes; const AValue: Byte); overload;
  1126. procedure ToBytesF(var Bytes: TIdBytes; const AValue: LongWord); overload;
  1127. procedure ToBytesF(var Bytes: TIdBytes; const AValue: Int64); overload;
  1128. procedure ToBytesF(var Bytes: TIdBytes; const AValue: TIdBytes; const ASize: Integer; const AIndex: Integer = 0); overload;
  1129. {$IFNDEF DOTNET}
  1130. // RLebeau - not using the same "ToBytesF" naming convention for RawToBytesF()
  1131. // in order to prevent ambiquious errors with ToBytesF(TIdBytes) above
  1132. procedure RawToBytesF(var Bytes: TIdBytes; const AValue; const ASize: Integer);
  1133. {$ENDIF}
  1134. function ToHex(const AValue: TIdBytes; const ACount: Integer = -1; const AIndex: Integer = 0): string; overload;
  1135. function ToHex(const AValue: array of LongWord): string; overload; // for IdHash
  1136. function BytesToString(const AValue: TIdBytes; AByteEncoding: TIdTextEncoding = nil
  1137. {$IFDEF STRING_IS_ANSI}; ADestEncoding: TIdTextEncoding = nil{$ENDIF}
  1138. ): string; overload;
  1139. function BytesToString(const AValue: TIdBytes; const AStartIndex: Integer;
  1140. const ALength: Integer = -1; AByteEncoding: TIdTextEncoding = nil
  1141. {$IFDEF STRING_IS_ANSI}; ADestEncoding: TIdTextEncoding = nil{$ENDIF}
  1142. ): string; overload;
  1143. // BytesToStringRaw() differs from BytesToString() in that it stores the
  1144. // byte octets as-is, whereas BytesToString() may decode character encodings
  1145. function BytesToStringRaw(const AValue: TIdBytes): string; overload;
  1146. function BytesToStringRaw(const AValue: TIdBytes; const AStartIndex: Integer;
  1147. const ALength: Integer = -1): string; overload;
  1148. function BytesToChar(const AValue: TIdBytes; const AIndex: Integer = 0;
  1149. AByteEncoding: TIdTextEncoding = nil
  1150. {$IFDEF STRING_IS_ANSI}; ADestEncoding: TIdTextEncoding = nil{$ENDIF}
  1151. ): Char; overload;
  1152. function BytesToChar(const AValue: TIdBytes; var VChar: Char; const AIndex: Integer = 0;
  1153. AByteEncoding: TIdTextEncoding = nil
  1154. {$IFDEF STRING_IS_ANSI}; ADestEncoding: TIdTextEncoding = nil{$ENDIF}
  1155. ): Integer; overload;
  1156. function BytesToShort(const AValue: TIdBytes; const AIndex: Integer = 0): Short;
  1157. function BytesToWord(const AValue: TIdBytes; const AIndex : Integer = 0): Word;
  1158. function BytesToLongWord(const AValue: TIdBytes; const AIndex : Integer = 0): LongWord;
  1159. function BytesToLongInt(const AValue: TIdBytes; const AIndex: Integer = 0): LongInt;
  1160. function BytesToInt64(const AValue: TIdBytes; const AIndex: Integer = 0): Int64;
  1161. function BytesToIPv4Str(const AValue: TIdBytes; const AIndex: Integer = 0): String;
  1162. procedure BytesToIPv6(const AValue: TIdBytes; var VAddress: TIdIPv6Address; const AIndex: Integer = 0);
  1163. {$IFNDEF DOTNET}
  1164. procedure BytesToRaw(const AValue: TIdBytes; var VBuffer; const ASize: Integer);
  1165. {$ENDIF}
  1166. // TIdBytes utilities
  1167. procedure AppendBytes(var VBytes: TIdBytes; const AToAdd: TIdBytes; const AIndex: Integer = 0; const ALength: Integer = -1);
  1168. procedure AppendByte(var VBytes: TIdBytes; const AByte: Byte);
  1169. procedure AppendString(var VBytes: TIdBytes; const AStr: String; const ALength: Integer = -1;
  1170. ADestEncoding: TIdTextEncoding = nil
  1171. {$IFDEF STRING_IS_ANSI}; ASrcEncoding: TIdTextEncoding = nil{$ENDIF}
  1172. );
  1173. procedure ExpandBytes(var VBytes: TIdBytes; const AIndex: Integer; const ACount: Integer; const AFillByte: Byte = 0);
  1174. procedure InsertBytes(var VBytes: TIdBytes; const ADestIndex: Integer; const ASource: TIdBytes; const ASourceIndex: Integer = 0);
  1175. procedure InsertByte(var VBytes: TIdBytes; const AByte: Byte; const AIndex: Integer);
  1176. procedure RemoveBytes(var VBytes: TIdBytes; const ACount: Integer; const AIndex: Integer = 0);
  1177. // Common Streaming routines
  1178. function ReadLnFromStream(AStream: TStream; var VLine: String; AMaxLineLength: Integer = -1;
  1179. AByteEncoding: TIdTextEncoding = nil
  1180. {$IFDEF STRING_IS_ANSI}; ADestEncoding: TIdTextEncoding = nil{$ENDIF}
  1181. ): Boolean; overload;
  1182. function ReadLnFromStream(AStream: TStream; AMaxLineLength: Integer = -1;
  1183. AExceptionIfEOF: Boolean = False; AByteEncoding: TIdTextEncoding = nil
  1184. {$IFDEF STRING_IS_ANSI}; ADestEncoding: TIdTextEncoding = nil{$ENDIF}
  1185. ): string; overload;
  1186. function ReadStringFromStream(AStream: TStream; ASize: Integer = -1; AByteEncoding: TIdTextEncoding = nil
  1187. {$IFDEF STRING_IS_ANSI}; ADestEncoding: TIdTextEncoding = nil{$ENDIF}
  1188. ): string; overload;
  1189. procedure WriteStringToStream(AStream: TStream; const AStr: string; ADestEncoding: TIdTextEncoding
  1190. {$IFDEF STRING_IS_ANSI}; ASrcEncoding: TIdTextEncoding = nil{$ENDIF}
  1191. ); overload;
  1192. procedure WriteStringToStream(AStream: TStream; const AStr: string; const ALength: Integer = -1;
  1193. const AIndex: Integer = 1; ADestEncoding: TIdTextEncoding = nil
  1194. {$IFDEF STRING_IS_ANSI}; ASrcEncoding: TIdTextEncoding = nil{$ENDIF}
  1195. ); overload;
  1196. function ReadCharFromStream(AStream: TStream; var VChar: Char; AByteEncoding: TIdTextEncoding = nil
  1197. {$IFDEF STRING_IS_ANSI}; ADestEncoding: TIdTextEncoding = nil{$ENDIF}
  1198. ): Integer;
  1199. function ReadTIdBytesFromStream(const AStream: TStream; var ABytes: TIdBytes;
  1200. const Count: TIdStreamSize; const AIndex: Integer = 0): TIdStreamSize;
  1201. procedure WriteTIdBytesToStream(const AStream: TStream; const ABytes: TIdBytes;
  1202. const ASize: Integer = -1; const AIndex: Integer = 0);
  1203. function ByteToHex(const AByte: Byte): string;
  1204. function ByteToOctal(const AByte: Byte): string;
  1205. function LongWordToHex(const ALongWord : LongWord) : String;
  1206. procedure CopyTIdBytes(const ASource: TIdBytes; const ASourceIndex: Integer;
  1207. var VDest: TIdBytes; const ADestIndex: Integer; const ALength: Integer);
  1208. procedure CopyTIdByteArray(const ASource: array of Byte; const ASourceIndex: Integer;
  1209. var VDest: TIdBytes; const ADestIndex: Integer; const ALength: Integer);
  1210. procedure CopyTIdChar(const ASource: Char; var VDest: TIdBytes; const ADestIndex: Integer;
  1211. ADestEncoding: TIdTextEncoding = nil
  1212. {$IFDEF STRING_IS_ANSI}; ASrcEncoding: TIdTextEncoding = nil{$ENDIF}
  1213. );
  1214. procedure CopyTIdShort(const ASource: Short; var VDest: TIdBytes; const ADestIndex: Integer);
  1215. procedure CopyTIdWord(const ASource: Word; var VDest: TIdBytes; const ADestIndex: Integer);
  1216. procedure CopyTIdLongInt(const ASource: LongInt; var VDest: TIdBytes; const ADestIndex: Integer);
  1217. procedure CopyTIdLongWord(const ASource: LongWord; var VDest: TIdBytes; const ADestIndex: Integer);
  1218. procedure CopyTIdInt64(const ASource: Int64; var VDest: TIdBytes; const ADestIndex: Integer);
  1219. procedure CopyTIdIPV6Address(const ASource: TIdIPv6Address; var VDest: TIdBytes; const ADestIndex: Integer);
  1220. procedure CopyTIdString(const ASource: String; var VDest: TIdBytes; const ADestIndex: Integer;
  1221. const ALength: Integer = -1; ADestEncoding: TIdTextEncoding = nil
  1222. {$IFDEF STRING_IS_ANSI}; ASrcEncoding: TIdTextEncoding = nil{$ENDIF}
  1223. ); overload;
  1224. procedure CopyTIdString(const ASource: String; const ASourceIndex: Integer;
  1225. var VDest: TIdBytes; const ADestIndex: Integer; const ALength: Integer = -1;
  1226. ADestEncoding: TIdTextEncoding = nil
  1227. {$IFDEF STRING_IS_ANSI}; ASrcEncoding: TIdTextEncoding = nil{$ENDIF}
  1228. ); overload;
  1229. // Need to change prob not to use this set
  1230. function CharPosInSet(const AString: string; const ACharPos: Integer; const ASet: String): Integer;
  1231. function CharIsInSet(const AString: string; const ACharPos: Integer; const ASet: String): Boolean;
  1232. function CharIsInEOL(const AString: string; const ACharPos: Integer): Boolean;
  1233. function CharEquals(const AString: string; const ACharPos: Integer; const AValue: Char): Boolean;
  1234. function ByteIndex(const AByte: Byte; const ABytes: TIdBytes; const AStartIndex: Integer = 0): Integer;
  1235. function ByteIdxInSet(const ABytes: TIdBytes; const AIndex: Integer; const ASet: TIdBytes): Integer;
  1236. function ByteIsInSet(const ABytes: TIdBytes; const AIndex: Integer; const ASet: TIdBytes): Boolean;
  1237. function ByteIsInEOL(const ABytes: TIdBytes; const AIndex: Integer): Boolean;
  1238. function CompareDate(const D1, D2: TDateTime): Integer;
  1239. function CurrentProcessId: TIdPID;
  1240. // RLebeau: the input of these two functions must be in GMT
  1241. function DateTimeGMTToHttpStr(const GMTValue: TDateTime) : String;
  1242. function DateTimeGMTToCookieStr(const GMTValue: TDateTime; const AUseNetscapeFmt: Boolean = True) : String;
  1243. // RLebeau: the input of these functions must be in local time
  1244. function DateTimeToInternetStr(const Value: TDateTime; const AUseGMTStr: Boolean = False) : String; {$IFDEF HAS_DEPRECATED}deprecated{$IFDEF HAS_DEPRECATED_MSG} 'Use LocalDateTimeToGMT()'{$ENDIF};{$ENDIF}
  1245. function DateTimeToGmtOffSetStr(ADateTime: TDateTime; const AUseGMTStr: Boolean = False): string; {$IFDEF HAS_DEPRECATED}deprecated{$IFDEF HAS_DEPRECATED_MSG} 'Use UTCOffsetToStr()'{$ENDIF};{$ENDIF}
  1246. function LocalDateTimeToHttpStr(const Value: TDateTime) : String;
  1247. function LocalDateTimeToCookieStr(const Value: TDateTime; const AUseNetscapeFmt: Boolean = True) : String;
  1248. function LocalDateTimeToGMT(const Value: TDateTime; const AUseGMTStr: Boolean = False) : String;
  1249. procedure DebugOutput(const AText: string);
  1250. function Fetch(var AInput: string; const ADelim: string = IdFetchDelimDefault;
  1251. const ADelete: Boolean = IdFetchDeleteDefault;
  1252. const ACaseSensitive: Boolean = IdFetchCaseSensitiveDefault): string;
  1253. function FetchCaseInsensitive(var AInput: string; const ADelim: string = IdFetchDelimDefault;
  1254. const ADelete: Boolean = IdFetchDeleteDefault): string;
  1255. // TODO: add an index parameter
  1256. procedure FillBytes(var VBytes : TIdBytes; const ACount : Integer; const AValue : Byte);
  1257. function CurrentThreadId: TIdThreadID;
  1258. function GetThreadHandle(AThread: TThread): TIdThreadHandle;
  1259. //GetTickDiff required because GetTickCount will wrap
  1260. function GetTickDiff(const AOldTickCount, ANewTickCount: LongWord): LongWord; //IdICMP uses it
  1261. procedure IdDelete(var s: string; AOffset, ACount: Integer);
  1262. procedure IdInsert(const Source: string; var S: string; Index: Integer);
  1263. {$IFNDEF DOTNET}
  1264. function IdPorts: TList;
  1265. {$ENDIF}
  1266. function iif(ATest: Boolean; const ATrue: Integer; const AFalse: Integer): Integer; overload;
  1267. function iif(ATest: Boolean; const ATrue: string; const AFalse: string = ''): string; overload; { do not localize }
  1268. function iif(ATest: Boolean; const ATrue: Boolean; const AFalse: Boolean): Boolean; overload;
  1269. function iif(const AEncoding, ADefEncoding: TIdTextEncoding; ADefEncodingType: IdAnsiEncodingType = encASCII): TIdTextEncoding; overload;
  1270. function InMainThread: Boolean;
  1271. function IPv6AddressToStr(const AValue: TIdIPv6Address): string;
  1272. //Note that there is NO need for Big Endian byte order functions because
  1273. //that's done through HostToNetwork byte order functions.
  1274. function HostToLittleEndian(const AValue : Word) : Word; overload;
  1275. function HostToLittleEndian(const AValue : LongWord): LongWord; overload;
  1276. function HostToLittleEndian(const AValue : Integer): Integer; overload;
  1277. function LittleEndianToHost(const AValue : Word) : Word; overload;
  1278. function LittleEndianToHost(const AValue : LongWord): LongWord; overload;
  1279. function LittleEndianToHost(const AValue : Integer): Integer; overload;
  1280. procedure WriteMemoryStreamToStream(Src: TMemoryStream; Dest: TStream; Count: TIdStreamSize);
  1281. {$IFNDEF DOTNET_EXCLUDE}
  1282. function IsCurrentThread(AThread: TThread): boolean;
  1283. {$ENDIF}
  1284. function IPv4ToDWord(const AIPAddress: string): LongWord; overload;
  1285. function IPv4ToDWord(const AIPAddress: string; var VErr: Boolean): LongWord; overload;
  1286. function IPv4ToHex(const AIPAddress: string; const ADotted: Boolean = False): string;
  1287. function IPv4ToOctal(const AIPAddress: string): string;
  1288. procedure IPv6ToIdIPv6Address(const AIPAddress: String; var VAddress: TIdIPv6Address); overload;
  1289. procedure IPv6ToIdIPv6Address(const AIPAddress: String; var VAddress: TIdIPv6Address; var VErr : Boolean); overload;
  1290. function IsAlpha(const AChar: Char): Boolean; overload;
  1291. function IsAlpha(const AString: String; const ALength: Integer = -1; const AIndex: Integer = 1): Boolean; overload;
  1292. function IsAlphaNumeric(const AChar: Char): Boolean; overload;
  1293. function IsAlphaNumeric(const AString: String; const ALength: Integer = -1; const AIndex: Integer = 1): Boolean; overload;
  1294. function IsASCII(const AByte: Byte): Boolean; overload;
  1295. function IsASCII(const ABytes: TIdBytes): Boolean; overload;
  1296. function IsASCIILDH(const AByte: Byte): Boolean; overload;
  1297. function IsASCIILDH(const ABytes: TIdBytes): Boolean; overload;
  1298. function IsHexidecimal(const AChar: Char): Boolean; overload;
  1299. function IsHexidecimal(const AString: string; const ALength: Integer = -1; const AIndex: Integer = 1): Boolean; overload;
  1300. function IsNumeric(const AChar: Char): Boolean; overload;
  1301. function IsNumeric(const AString: string): Boolean; overload;
  1302. function IsNumeric(const AString: string; const ALength: Integer; const AIndex: Integer = 1): Boolean; overload;
  1303. function IsOctal(const AChar: Char): Boolean; overload;
  1304. function IsOctal(const AString: string; const ALength: Integer = -1; const AIndex: Integer = 1): Boolean; overload;
  1305. {$IFNDEF DOTNET}
  1306. function InterlockedExchangeTHandle(var VTarget: THandle; const AValue: THandle): THandle;
  1307. function InterlockedCompareExchangePtr(var VTarget: Pointer; const AValue, Compare: Pointer): Pointer;
  1308. {$ENDIF}
  1309. function MakeCanonicalIPv4Address(const AAddr: string): string;
  1310. function MakeCanonicalIPv6Address(const AAddr: string): string;
  1311. function MakeDWordIntoIPv4Address(const ADWord: LongWord): string;
  1312. function IndyMin(const AValueOne, AValueTwo: Int64): Int64; overload;
  1313. function IndyMin(const AValueOne, AValueTwo: LongInt): LongInt; overload;
  1314. function IndyMin(const AValueOne, AValueTwo: Word): Word; overload;
  1315. function IndyMax(const AValueOne, AValueTwo: Int64): Int64; overload;
  1316. function IndyMax(const AValueOne, AValueTwo: LongInt): LongInt; overload;
  1317. function IndyMax(const AValueOne, AValueTwo: Word): Word; overload;
  1318. function IPv4MakeLongWordInRange(const AInt: Int64; const A256Power: Integer): LongWord;
  1319. {$IFNDEF DOTNET}
  1320. {$IFDEF REGISTER_EXPECTED_MEMORY_LEAK}
  1321. function IndyRegisterExpectedMemoryLeak(AAddress: Pointer): Boolean;
  1322. {$ENDIF}
  1323. {$ENDIF}
  1324. {$IFDEF UNIX}
  1325. function HackLoad(const ALibName : String; const ALibVersions : array of String) : HMODULE;
  1326. {$ENDIF}
  1327. {$IFNDEF DOTNET}
  1328. function MemoryPos(const ASubStr: string; MemBuff: PChar; MemorySize: Integer): Integer;
  1329. {$ENDIF}
  1330. function OffsetFromUTC: TDateTime;
  1331. function UTCOffsetToStr(const AOffset: TDateTime; const AUseGMTStr: Boolean = False): string;
  1332. function PosIdx(const ASubStr, AStr: string; AStartPos: LongWord = 0): LongWord; //For "ignoreCase" use AnsiUpperCase
  1333. function PosInSmallIntArray(const ASearchInt: SmallInt; const AArray: array of SmallInt): Integer;
  1334. function PosInStrArray(const SearchStr: string; const Contents: array of string; const CaseSensitive: Boolean = True): Integer;
  1335. {$IFNDEF DOTNET}
  1336. function ServicesFilePath: string;
  1337. {$ENDIF}
  1338. procedure IndySetThreadPriority(AThread: TThread; const APriority: TIdThreadPriority; const APolicy: Integer = -MaxInt);
  1339. procedure SetThreadName(const AName: string; {$IFDEF DOTNET}AThread: System.Threading.Thread = nil{$ELSE}AThreadID: LongWord = $FFFFFFFF{$ENDIF});
  1340. procedure IndySleep(ATime: LongWord);
  1341. //in Integer(Strings.Objects[i]) - column position in AData
  1342. procedure SplitColumnsNoTrim(const AData: string; AStrings: TStrings; const ADelim: string = ' '); {Do not Localize}
  1343. procedure SplitColumns(const AData: string; AStrings: TStrings; const ADelim: string = ' '); {Do not Localize}
  1344. function StartsWithACE(const ABytes: TIdBytes): Boolean;
  1345. function StringsReplace(const S: String; const OldPattern, NewPattern: array of string): string;
  1346. function ReplaceOnlyFirst(const S, OldPattern, NewPattern: string): string;
  1347. function TextIsSame(const A1, A2: string): Boolean;
  1348. function TextStartsWith(const S, SubS: string): Boolean;
  1349. function TextEndsWith(const S, SubS: string): Boolean;
  1350. function IndyUpperCase(const A1: string): string;
  1351. function IndyLowerCase(const A1: string): string;
  1352. function IndyCompareStr(const A1: string; const A2: string): Integer;
  1353. function Ticks: LongWord;
  1354. procedure ToDo(const AMsg: string);
  1355. function TwoByteToWord(AByte1, AByte2: Byte): Word;
  1356. function IndyIndexOf(AStrings: TStrings; const AStr: string; const ACaseSensitive: Boolean = False): Integer;{$IFDEF HAS_TStringList_CaseSensitive} overload;{$ENDIF}
  1357. {$IFDEF HAS_TStringList_CaseSensitive}
  1358. function IndyIndexOf(AStrings: TStringList; const AStr: string; const ACaseSensitive: Boolean = False): Integer; overload;
  1359. {$ENDIF}
  1360. function IndyIndexOfName(AStrings: TStrings; const AStr: string; const ACaseSensitive: Boolean = False): Integer;{$IFDEF HAS_TStringList_CaseSensitive} overload;{$ENDIF}
  1361. {$IFDEF HAS_TStringList_CaseSensitive}
  1362. function IndyIndexOfName(AStrings: TStringList; const AStr: string; const ACaseSensitive: Boolean = False): Integer; overload;
  1363. {$ENDIF}
  1364. var
  1365. {$IFDEF UNIX}
  1366. // For linux the user needs to set this variable to be accurate where used (mail, etc)
  1367. GOffsetFromUTC: TDateTime = 0;
  1368. {$ENDIF}
  1369. IndyPos: TPosProc = nil;
  1370. {$IFDEF UNIX}
  1371. const
  1372. {$IFDEF DARWIN}
  1373. LIBEXT = '.dylib'; {do not localize}
  1374. {$ELSE}
  1375. LIBEXT = '.so'; {do not localize}
  1376. {$ENDIF}
  1377. {$ENDIF}
  1378. implementation
  1379. uses
  1380. {$IFDEF USE_VCL_POSIX}
  1381. Posix.SysSelect,
  1382. Posix.SysSocket,
  1383. Posix.Time, Posix.SysTime,
  1384. {$ENDIF}
  1385. {$IFDEF VCL_CROSS_COMPILE}
  1386. {$IFDEF MACOSX}
  1387. CoreServices,
  1388. {$ENDIF}
  1389. {$ENDIF}
  1390. {$IFDEF REGISTER_EXPECTED_MEMORY_LEAK}
  1391. {$IFDEF USE_FASTMM4}FastMM4,{$ENDIF}
  1392. {$ENDIF}
  1393. {$IFDEF USE_LIBC}Libc,{$ENDIF}
  1394. {$IFDEF HAS_UNIT_DateUtils}DateUtils,{$ENDIF}
  1395. //do not bring in our IdIconv unit if we are using the libc unit directly.
  1396. {$IFDEF USE_ICONV_UNIT}IdIconv, {$ENDIF}
  1397. IdResourceStrings,
  1398. IdStream;
  1399. {$IFDEF FPC}
  1400. {$IFDEF WINCE}
  1401. //FreePascal for WindowsCE may not define these.
  1402. const
  1403. CP_UTF7 = 65000;
  1404. CP_UTF8 = 65001;
  1405. {$ENDIF}
  1406. {$ENDIF}
  1407. procedure EnsureEncoding(var VEncoding : TIdTextEncoding; ADefEncoding: IdAnsiEncodingType = encIndyDefault);
  1408. {$IFDEF USEINLINE}inline;{$ENDIF}
  1409. begin
  1410. if VEncoding = nil then
  1411. begin
  1412. if ADefEncoding = encIndyDefault then begin
  1413. ADefEncoding := GIdDefaultAnsiEncoding;
  1414. end;
  1415. case ADefEncoding of
  1416. encASCII: VEncoding := IndyASCIIEncoding;
  1417. encUTF7: VEncoding := TIdTextEncoding.UTF7;
  1418. encUTF8: VEncoding := IndyUTF8Encoding;
  1419. enc8Bit: VEncoding := Indy8BitEncoding;
  1420. else
  1421. VEncoding := TIdTextEncoding.Default;
  1422. end;
  1423. end;
  1424. end;
  1425. {$IFDEF FPC}
  1426. {$IFNDEF WINDOWS}
  1427. //FreePascal may not define this for non-Windows systems.
  1428. //#define MAKEWORD(a, b) ((WORD)(((BYTE)(a)) | ((WORD)((BYTE)(b))) << 8))
  1429. function MakeWord(const a, b : Byte) : Word;
  1430. {$IFDEF USE_INLINE}inline;{$ENDIF}
  1431. begin
  1432. Result := (a) or (b shl 8);
  1433. end;
  1434. {$ENDIF}
  1435. {$ENDIF}
  1436. {$IFNDEF DOTNET}
  1437. var
  1438. GIdPorts: TList = nil;
  1439. GId8BitEncoding: TIdTextEncoding = nil;
  1440. // RLebeau: ASCII is handled separate from other standard encodings
  1441. // because we need to do special handling of its codepage regardless
  1442. // of whether TIdTextEncoding is implemented natively or manually...
  1443. GIdASCIIEncoding: TIdTextEncoding = nil;
  1444. // RLebeau: UTF-8 is handled separate from other standard encodings
  1445. // because we need to avoid the MB_ERR_INVALID_CHARS flag regardless
  1446. // of whether TIdTextEncoding is implemented natively or manually...
  1447. GIdUTF8Encoding: TIdTextEncoding = nil;
  1448. {$ENDIF}
  1449. {$IFNDEF TIdTextEncoding_IS_NATIVE}
  1450. var
  1451. GIdBEUTF16Encoding: TIdTextEncoding = nil;
  1452. GIdDefaultEncoding: TIdTextEncoding = nil;
  1453. GIdLEUTF16Encoding: TIdTextEncoding = nil;
  1454. GIdUTF7Encoding: TIdTextEncoding = nil;
  1455. { TIdTextEncoding }
  1456. class function TIdTextEncoding.Convert(ASource, ADestination: TIdTextEncoding;
  1457. const ABytes: TIdBytes): TIdBytes;
  1458. begin
  1459. Result := ADestination.GetBytes(ASource.GetChars(ABytes));
  1460. end;
  1461. class function TIdTextEncoding.Convert(ASource, ADestination: TIdTextEncoding;
  1462. const ABytes: TIdBytes; AStartIndex, ACount: Integer): TIdBytes;
  1463. begin
  1464. Result := ADestination.GetBytes(ASource.GetChars(ABytes, AStartIndex, ACount));
  1465. end;
  1466. class procedure TIdTextEncoding.FreeEncodings;
  1467. begin
  1468. FreeAndNil(GIdDefaultEncoding);
  1469. // RLebeau: ASCII is handled separate from other standard encodings
  1470. // because we need to do special handling of its codepage regardless
  1471. // of whether TIdTextEncoding is implemented natively or manually...
  1472. //FreeAndNil(GIdASCIIEncoding);
  1473. // RLebeau: UTF-8 is handled separate from other standard encodings
  1474. // because we need to avoid the MB_ERR_INVALID_CHARS flag regardless
  1475. // of whether TIdTextEncoding is implemented natively or manually...
  1476. //FreeAndNil(GIdUTF8Encoding);
  1477. FreeAndNil(GIdUTF7Encoding);
  1478. FreeAndNil(GIdLEUTF16Encoding);
  1479. FreeAndNil(GIdBEUTF16Encoding);
  1480. end;
  1481. {$IFDEF HAS_CLASSPROPERTIES}
  1482. class function TIdTextEncoding.GetASCII: TIdTextEncoding;
  1483. {$ELSE}
  1484. class function TIdTextEncoding.ASCII: TIdTextEncoding;
  1485. {$ENDIF}
  1486. begin
  1487. // RLebeau: ASCII is handled separate from other standard encodings
  1488. // because we need to do special handling of its codepage regardless
  1489. // of whether TIdTextEncoding is implemented natively or manually...
  1490. Result := IndyASCIIEncoding(True);
  1491. end;
  1492. {$IFDEF HAS_CLASSPROPERTIES}
  1493. class function TIdTextEncoding.GetBigEndianUnicode: TIdTextEncoding;
  1494. {$ELSE}
  1495. class function TIdTextEncoding.BigEndianUnicode: TIdTextEncoding;
  1496. {$ENDIF}
  1497. var
  1498. LEncoding: TIdTextEncoding;
  1499. begin
  1500. if GIdBEUTF16Encoding = nil then
  1501. begin
  1502. LEncoding := TIdUTF16BigEndianEncoding.Create;
  1503. if InterlockedCompareExchangePtr(Pointer(GIdBEUTF16Encoding), LEncoding, nil) <> nil then
  1504. LEncoding.Free;
  1505. end;
  1506. Result := GIdBEUTF16Encoding;
  1507. end;
  1508. class function TIdTextEncoding.GetBufferEncoding(const ABuffer: TIdBytes; var AEncoding: TIdTextEncoding): Integer;
  1509. function ContainsPreamble(const Buffer, Signature: TIdBytes): Boolean;
  1510. var
  1511. I: Integer;
  1512. begin
  1513. if Length(Buffer) >= Length(Signature) then
  1514. begin
  1515. Result := True;
  1516. for I := 0 to Length(Signature)-1 do
  1517. begin
  1518. if Buffer[I] <> Signature [I] then
  1519. begin
  1520. Result := False;
  1521. Break;
  1522. end;
  1523. end;
  1524. end else begin
  1525. Result := False;
  1526. end;
  1527. end;
  1528. var
  1529. Preamble: TIdBytes;
  1530. begin
  1531. Result := 0;
  1532. Preamble := nil; // keep the compiler happy
  1533. if AEncoding = nil then
  1534. begin
  1535. // Find the appropriate encoding
  1536. if ContainsPreamble(ABuffer, TIdTextEncoding.Unicode.GetPreamble) then begin
  1537. AEncoding := TIdTextEncoding.Unicode;
  1538. end
  1539. else if ContainsPreamble(ABuffer, TIdTextEncoding.BigEndianUnicode.GetPreamble) then begin
  1540. AEncoding := TIdTextEncoding.BigEndianUnicode;
  1541. end
  1542. else if ContainsPreamble(ABuffer, IndyUTF8Encoding.GetPreamble) then begin
  1543. AEncoding := IndyUTF8Encoding;
  1544. end else
  1545. begin
  1546. AEncoding := TIdTextEncoding.Default;
  1547. end;
  1548. Result := Length(AEncoding.GetPreamble);
  1549. end else
  1550. begin
  1551. Preamble := AEncoding.GetPreamble;
  1552. if ContainsPreamble(ABuffer, Preamble) then
  1553. Result := Length(Preamble);
  1554. end;
  1555. end;
  1556. function TIdTextEncoding.GetByteCount(const AChars: TIdWideChars): Integer;
  1557. begin
  1558. Result := GetByteCount(AChars, 0, Length(AChars));
  1559. end;
  1560. function TIdTextEncoding.GetByteCount(const AChars: TIdWideChars; ACharIndex,
  1561. ACharCount: Integer): Integer;
  1562. begin
  1563. if ACharIndex < 0 then
  1564. raise Exception.CreateResFmt(@RSCharIndexOutOfBounds, [ACharIndex]);
  1565. if ACharCount < 0 then
  1566. raise Exception.CreateResFmt(@RSInvalidCharCount, [ACharCount]);
  1567. if (Length(AChars) - ACharIndex) < ACharCount then
  1568. raise Exception.CreateResFmt(@RSInvalidCharCount, [ACharCount]);
  1569. if ACharCount > 0 then begin
  1570. Result := GetByteCount(@AChars[ACharIndex], ACharCount);
  1571. end else begin
  1572. Result := 0;
  1573. end;
  1574. end;
  1575. function TIdTextEncoding.GetByteCount(const AStr: TIdUnicodeString): Integer;
  1576. begin
  1577. Result := GetByteCount(PWideChar(AStr), Length(AStr));
  1578. end;
  1579. function TIdTextEncoding.GetByteCount(const AStr: TIdUnicodeString; ACharIndex, ACharCount: Integer): Integer;
  1580. begin
  1581. if ACharIndex < 1 then
  1582. raise Exception.CreateResFmt(@RSCharIndexOutOfBounds, [ACharIndex]);
  1583. if ACharCount < 0 then
  1584. raise Exception.CreateResFmt(@RSInvalidCharCount, [ACharCount]);
  1585. if (Length(AStr) - ACharIndex + 1) < ACharCount then
  1586. raise Exception.CreateResFmt(@RSInvalidCharCount, [ACharCount]);
  1587. if ACharCount > 0 then begin
  1588. Result := GetByteCount(PWideChar(@AStr[ACharIndex]), ACharCount);
  1589. end else begin
  1590. Result := 0;
  1591. end;
  1592. end;
  1593. function TIdTextEncoding.GetBytes(const AChars: TIdWideChars): TIdBytes;
  1594. var
  1595. Len: Integer;
  1596. begin
  1597. Len := GetByteCount(AChars);
  1598. SetLength(Result, Len);
  1599. if Len > 0 then begin
  1600. GetBytes(AChars, 0, Length(AChars), Result, 0);
  1601. end;
  1602. end;
  1603. function TIdTextEncoding.GetBytes(const AChars: TIdWideChars; ACharIndex, ACharCount: Integer;
  1604. var VBytes: TIdBytes; AByteIndex: Integer): Integer;
  1605. var
  1606. Len: Integer;
  1607. begin
  1608. if (AChars = nil) and (ACharCount <> 0) then
  1609. raise Exception.CreateRes(@RSInvalidSourceArray);
  1610. if (VBytes = nil) and (ACharCount <> 0) then
  1611. raise Exception.CreateRes(@RSInvalidDestinationArray);
  1612. if ACharIndex < 0 then
  1613. raise Exception.CreateResFmt(@RSCharIndexOutOfBounds, [ACharIndex]);
  1614. if ACharCount < 0 then
  1615. raise Exception.CreateResFmt(@RSInvalidCharCount, [ACharCount]);
  1616. if (Length(AChars) - ACharIndex) < ACharCount then
  1617. raise Exception.CreateResFmt(@RSInvalidCharCount, [ACharCount]);
  1618. Len := Length(VBytes);
  1619. if (AByteIndex < 0) or (AByteIndex > Len) then
  1620. raise Exception.CreateResFmt(@RSInvalidDestinationIndex, [AByteIndex]);
  1621. if Len - AByteIndex < GetByteCount(AChars, ACharIndex, ACharCount) then
  1622. raise Exception.CreateRes(@RSInvalidDestinationArray);
  1623. Len := Len - AByteIndex;
  1624. if (ACharCount > 0) and (Len > 0) then begin
  1625. Result := GetBytes(@AChars[ACharIndex], ACharCount, @VBytes[AByteIndex], Len);
  1626. end else begin
  1627. Result := 0;
  1628. end;
  1629. end;
  1630. function TIdTextEncoding.GetBytes(const AStr: TIdUnicodeString): TIdBytes;
  1631. var
  1632. Len: Integer;
  1633. begin
  1634. Len := GetByteCount(AStr);
  1635. SetLength(Result, Len);
  1636. if Len > 0 then begin
  1637. GetBytes(AStr, 1, Length(AStr), Result, 0);
  1638. end;
  1639. end;
  1640. function TIdTextEncoding.GetBytes(const AStr: TIdUnicodeString; ACharIndex, ACharCount: Integer;
  1641. var VBytes: TIdBytes; AByteIndex: Integer): Integer;
  1642. var
  1643. Len: Integer;
  1644. begin
  1645. if (VBytes = nil) and (ACharCount <> 0) then
  1646. raise Exception.CreateRes(@RSInvalidSourceArray);
  1647. if ACharIndex < 1 then
  1648. raise Exception.CreateResFmt(@RSCharIndexOutOfBounds, [ACharIndex]);
  1649. if ACharCount < 0 then
  1650. raise Exception.CreateResFmt(@RSInvalidCharCount, [ACharCount]);
  1651. if (Length(AStr) - ACharIndex + 1) < ACharCount then
  1652. raise Exception.CreateResFmt(@RSInvalidCharCount, [ACharCount]);
  1653. Len := Length(VBytes);
  1654. if (AByteIndex < 0) or (AByteIndex > Len) then
  1655. raise Exception.CreateResFmt(@RSInvalidDestinationIndex, [AByteIndex]);
  1656. if Len - AByteIndex < GetByteCount(AStr, ACharIndex, ACharCount) then
  1657. raise Exception.CreateRes(@RSInvalidDestinationArray);
  1658. Len := Len - AByteIndex;
  1659. if (ACharCount > 0) and (Len > 0) then begin
  1660. Result := GetBytes(@AStr[ACharIndex], ACharCount, @VBytes[AByteIndex], Len);
  1661. end else begin
  1662. Result := 0
  1663. end;
  1664. end;
  1665. function TIdTextEncoding.GetCharCount(const ABytes: TIdBytes): Integer;
  1666. begin
  1667. Result := GetCharCount(ABytes, 0, Length(ABytes));
  1668. end;
  1669. function TIdTextEncoding.GetCharCount(const ABytes: TIdBytes; AByteIndex, AByteCount: Integer): Integer;
  1670. begin
  1671. if (ABytes = nil) and (AByteCount <> 0) then
  1672. raise Exception.CreateRes(@RSInvalidSourceArray);
  1673. if AByteIndex < 0 then
  1674. raise Exception.CreateResFmt(@RSByteIndexOutOfBounds, [AByteIndex]);
  1675. if AByteCount < 0 then
  1676. raise Exception.CreateResFmt(@RSInvalidCharCount, [AByteCount]);
  1677. if (Length(ABytes) - AByteIndex) < AByteCount then
  1678. raise Exception.CreateResFmt(@RSInvalidCharCount, [AByteCount]);
  1679. if AByteCount > 0 then begin
  1680. Result := GetCharCount(@ABytes[AByteIndex], AByteCount);
  1681. end else begin
  1682. Result := 0
  1683. end;
  1684. end;
  1685. function TIdTextEncoding.GetChars(const ABytes: TIdBytes): TIdWideChars;
  1686. begin
  1687. Result := GetChars(ABytes, 0, Length(ABytes));
  1688. end;
  1689. function TIdTextEncoding.GetChars(const ABytes: TIdBytes; AByteIndex, AByteCount: Integer): TIdWideChars;
  1690. var
  1691. Len: Integer;
  1692. begin
  1693. if (ABytes = nil) and (AByteCount <> 0) then
  1694. raise Exception.CreateRes(@RSInvalidSourceArray);
  1695. if AByteIndex < 0 then
  1696. raise Exception.CreateResFmt(@RSByteIndexOutOfBounds, [AByteIndex]);
  1697. if AByteCount < 0 then
  1698. raise Exception.CreateResFmt(@RSInvalidCharCount, [AByteCount]);
  1699. if (Length(ABytes) - AByteIndex) < AByteCount then
  1700. raise Exception.CreateResFmt(@RSInvalidCharCount, [AByteCount]);
  1701. Len := GetCharCount(ABytes, AByteIndex, AByteCount);
  1702. SetLength(Result, Len);
  1703. if Len > 0 then begin
  1704. GetChars(@ABytes[AByteIndex], AByteCount, PWideChar(Result), Len);
  1705. end;
  1706. end;
  1707. function TIdTextEncoding.GetChars(const ABytes: TIdBytes; AByteIndex, AByteCount: Integer;
  1708. var VChars: TIdWideChars; ACharIndex: Integer): Integer;
  1709. var
  1710. LCharCount: Integer;
  1711. begin
  1712. if (ABytes = nil) and (AByteCount <> 0) then
  1713. raise Exception.CreateRes(@RSInvalidSourceArray);
  1714. if AByteIndex < 0 then
  1715. raise Exception.CreateResFmt(@RSByteIndexOutOfBounds, [AByteIndex]);
  1716. if AByteCount < 0 then
  1717. raise Exception.CreateResFmt(@RSInvalidCharCount, [AByteCount]);
  1718. if (Length(ABytes) - AByteIndex) < AByteCount then
  1719. raise Exception.CreateResFmt(@RSInvalidCharCount, [AByteCount]);
  1720. LCharCount := GetCharCount(ABytes, AByteIndex, AByteCount);
  1721. if (ACharIndex < 0) or (ACharIndex > Length(VChars)) then
  1722. raise Exception.CreateResFmt(@RSInvalidDestinationIndex, [ACharIndex]);
  1723. if ACharIndex + LCharCount > Length(VChars) then
  1724. raise Exception.CreateRes(@RSInvalidDestinationArray);
  1725. if (AByteCount > 0) and (LCharCount > 0) then begin
  1726. Result := GetChars(@ABytes[AByteIndex], AByteCount, @VChars[ACharIndex], LCharCount);
  1727. end else begin
  1728. Result := 0
  1729. end;
  1730. end;
  1731. {$IFDEF HAS_CLASSPROPERTIES}
  1732. class function TIdTextEncoding.GetDefault: TIdTextEncoding;
  1733. {$ELSE}
  1734. class function TIdTextEncoding.Default: TIdTextEncoding;
  1735. {$ENDIF}
  1736. var
  1737. LEncoding: TIdTextEncoding;
  1738. begin
  1739. if GIdDefaultEncoding = nil then
  1740. begin
  1741. {$IFDEF USE_ICONV}
  1742. LEncoding := TIdMBCSEncoding.Create('ASCII');
  1743. {$ELSE}
  1744. {$IFDEF WINDOWS}
  1745. LEncoding := TIdMBCSEncoding.Create(CP_ACP, 0, 0);
  1746. {$ELSE}
  1747. ToDo('Default property of TIdTextEncoding class is not implemented for this platform yet'); {do not localize}
  1748. {$ENDIF}
  1749. {$ENDIF}
  1750. if InterlockedCompareExchangePtr(Pointer(GIdDefaultEncoding), LEncoding, nil) <> nil then
  1751. LEncoding.Free;
  1752. end;
  1753. Result := GIdDefaultEncoding;
  1754. end;
  1755. {$IFDEF USE_ICONV}
  1756. class function TIdTextEncoding.GetEncoding(const ACharSet: String): TIdTextEncoding;
  1757. begin
  1758. Result := TIdMBCSEncoding.Create(ACharSet);
  1759. end;
  1760. {$ELSE}
  1761. {$IFDEF WINDOWS}
  1762. class function TIdTextEncoding.GetEncoding(ACodePage: Integer): TIdTextEncoding;
  1763. begin
  1764. case ACodePage of
  1765. 1200: Result := TIdUTF16LittleEndianEncoding.Create;
  1766. 1201: Result := TIdUTF16BigEndianEncoding.Create;
  1767. 65000: Result := TIdUTF7Encoding.Create;
  1768. 20127:
  1769. // RLebeau: 20127 is the official codepage for ASCII,
  1770. // but not all OS versions support that codepage...
  1771. Result := IndyASCIIEncoding(False);
  1772. 65001:
  1773. // RLebeau: UTF-8 is handled separate from other standard
  1774. // encodings because we need to avoid the MB_ERR_INVALID_CHARS
  1775. // flag regardless of whether TIdTextEncoding is implemented
  1776. // natively or manually...
  1777. Result := IndyUTF8Encoding(False);
  1778. else
  1779. Result := TIdMBCSEncoding.Create(ACodePage);
  1780. end;
  1781. end;
  1782. {$ENDIF}
  1783. {$ENDIF}
  1784. function TIdTextEncoding.GetString(const ABytes: TIdBytes): TIdUnicodeString;
  1785. begin
  1786. Result := GetString(ABytes, 0, Length(ABytes));
  1787. end;
  1788. function TIdTextEncoding.GetString(const ABytes: TIdBytes; AByteIndex, AByteCount: Integer): TIdUnicodeString;
  1789. var
  1790. LChars: TIdWideChars;
  1791. begin
  1792. LChars := GetChars(ABytes, AByteIndex, AByteCount);
  1793. SetString(Result, PWideChar(LChars), Length(LChars));
  1794. end;
  1795. {$IFDEF HAS_CLASSPROPERTIES}
  1796. class function TIdTextEncoding.GetUnicode: TIdTextEncoding;
  1797. {$ELSE}
  1798. class function TIdTextEncoding.Unicode: TIdTextEncoding;
  1799. {$ENDIF}
  1800. var
  1801. LEncoding: TIdTextEncoding;
  1802. begin
  1803. if GIdLEUTF16Encoding = nil then
  1804. begin
  1805. LEncoding := TIdUTF16LittleEndianEncoding.Create;
  1806. if InterlockedCompareExchangePtr(Pointer(GIdLEUTF16Encoding), LEncoding, nil) <> nil then
  1807. LEncoding.Free;
  1808. end;
  1809. Result := GIdLEUTF16Encoding;
  1810. end;
  1811. {$IFDEF HAS_CLASSPROPERTIES}
  1812. class function TIdTextEncoding.GetUTF7: TIdTextEncoding;
  1813. {$ELSE}
  1814. class function TIdTextEncoding.UTF7: TIdTextEncoding;
  1815. {$ENDIF}
  1816. var
  1817. LEncoding: TIdTextEncoding;
  1818. begin
  1819. if GIdUTF7Encoding = nil then
  1820. begin
  1821. LEncoding := TIdUTF7Encoding.Create;
  1822. if InterlockedCompareExchangePtr(Pointer(GIdUTF7Encoding), LEncoding, nil) <> nil then
  1823. LEncoding.Free;
  1824. end;
  1825. Result := GIdUTF7Encoding;
  1826. end;
  1827. {$IFDEF HAS_CLASSPROPERTIES}
  1828. class function TIdTextEncoding.GetUTF8: TIdTextEncoding;
  1829. {$ELSE}
  1830. class function TIdTextEncoding.UTF8: TIdTextEncoding;
  1831. {$ENDIF}
  1832. begin
  1833. // RLebeau: UTF-8 is handled separate from other standard encodings
  1834. // because we need to avoid the MB_ERR_INVALID_CHARS flag regardless
  1835. // of whether TIdTextEncoding is implemented natively or manually...
  1836. Result := IndyUTF8Encoding(True);
  1837. end;
  1838. class function TIdTextEncoding.IsStandardEncoding(AEncoding: TIdTextEncoding): Boolean;
  1839. begin
  1840. Result := Assigned(AEncoding) and (
  1841. (AEncoding = GIdASCIIEncoding) or
  1842. (AEncoding = GIdBEUTF16Encoding) or
  1843. (AEncoding = GIdDefaultEncoding) or
  1844. (AEncoding = GIdLEUTF16Encoding) or
  1845. (AEncoding = GIdUTF7Encoding) or
  1846. (AEncoding = GIdUTF8Encoding)
  1847. );
  1848. end;
  1849. { TIdMBCSEncoding }
  1850. constructor TIdMBCSEncoding.Create;
  1851. begin
  1852. {$IFDEF USE_ICONV}
  1853. // TODO: figure out a way to determine this dynamically, or let the user specify a default...
  1854. Create('ASCII'); {do not localize}
  1855. {$ELSE}
  1856. {$IFDEF WINDOWS}
  1857. Create(CP_ACP, 0, 0);
  1858. {$ELSE}
  1859. ToDo('Constructor of TIdMBCSEncoding class is not implemented for this platform yet'); {do not localize}
  1860. {$ENDIF}
  1861. {$ENDIF}
  1862. end;
  1863. {$IFDEF USE_ICONV}
  1864. constructor TIdMBCSEncoding.Create(const CharSet: AnsiString);
  1865. const
  1866. // RLebeau: iconv() does not provide a maximum character byte size like
  1867. // Microsoft does, so have to determine the max bytes by manually encoding
  1868. // an actual Unicode codepoint. We'll encode the largest codepoint that
  1869. // UTF-16 supports, $10FFFD, for now...
  1870. cValue: array[0..1] of Word = ($DBFF, $DFFD);
  1871. begin
  1872. inherited Create;
  1873. FCharSet := CharSet;
  1874. FToUTF16 := iconv_open('UTF-16', PAnsiChar(CharSet)); {do not localize}
  1875. FFromUTF16 := iconv_open(PAnsiChar(CharSet), 'UTF-16'); {do not localize}
  1876. if (FToUTF16 = iconv_t(-1)) or (FFromUTF16 = iconv_t(-1)) then begin
  1877. if FToUTF16 <> iconv_t(-1) then begin
  1878. iconv_close(FToUTF16);
  1879. FToUTF16 := iconv_t(-1);
  1880. end;
  1881. if FFromUTF16 <> iconv_t(-1) then begin
  1882. iconv_close(FFromUTF16);
  1883. FFromUTF16 := iconv_t(-1);
  1884. end;
  1885. raise EIdException.CreateResFmt(@RSInvalidCharSet, [CharSet]);
  1886. end;
  1887. FMaxCharSize := GetByteCount(PWideChar(@cValue[0]), 2);
  1888. FIsSingleByte := FMaxCharSize = 1;
  1889. end;
  1890. destructor TIdMBCSEncoding.Destroy;
  1891. begin
  1892. if FToUTF16 <> iconv_t(-1) then begin
  1893. iconv_close(FToUTF16);
  1894. end;
  1895. if FFromUTF16 <> iconv_t(-1) then begin
  1896. iconv_close(FFromUTF16);
  1897. end;
  1898. inherited;
  1899. end;
  1900. {$ELSE}
  1901. {$IFDEF WINDOWS}
  1902. constructor TIdMBCSEncoding.Create(CodePage: Integer);
  1903. begin
  1904. Create(CodePage, 0, 0);
  1905. end;
  1906. constructor TIdMBCSEncoding.Create(CodePage, MBToWCharFlags, WCharToMBFlags: Integer);
  1907. var
  1908. LCPInfo: TCPInfo;
  1909. LError: Boolean;
  1910. begin
  1911. FCodePage := CodePage;
  1912. FMBToWCharFlags := MBToWCharFlags;
  1913. FWCharToMBFlags := WCharToMBFlags;
  1914. LError := not GetCPInfo(FCodePage, LCPInfo);
  1915. if LError and (FCodePage = 20127) then begin
  1916. // RLebeau: 20127 is the official codepage for ASCII, but not
  1917. // all OS versions support that codepage, so fallback to 1252
  1918. // or even 437...
  1919. FCodePage := 1252;
  1920. LError := not GetCPInfo(FCodePage, LCPInfo);
  1921. // just in case...
  1922. if LError then begin
  1923. FCodePage := 437;
  1924. LError := not GetCPInfo(FCodePage, LCPInfo);
  1925. end;
  1926. end;
  1927. if LError then begin
  1928. raise EIdException.CreateResFmt(@RSInvalidCodePage, [FCodePage]);
  1929. end;
  1930. FMaxCharSize := LCPInfo.MaxCharSize;
  1931. FIsSingleByte := FMaxCharSize = 1;
  1932. end;
  1933. {$ENDIF}
  1934. {$ENDIF}
  1935. function TIdMBCSEncoding.GetByteCount(Chars: PWideChar; CharCount: Integer): Integer;
  1936. {$IFDEF USE_ICONV}
  1937. var
  1938. LBytes: array[0..3] of Byte;
  1939. LCharsPtr, LBytesPtr: PAnsiChar;
  1940. LCharCount, LByteCount: size_t;
  1941. {$ENDIF}
  1942. begin
  1943. {$IFDEF USE_ICONV}
  1944. // RLebeau: iconv() does not allow for querying a pre-calculated byte size
  1945. // for the input like Microsoft does, so have to determine the max bytes
  1946. // by actually encoding the Unicode data to a real buffer. We'll encode
  1947. // to a small local buffer so we don't have to use a lot of memory...
  1948. Result := 0;
  1949. LCharsPtr := PAnsiChar(Chars);
  1950. LCharCount := CharCount * SizeOf(WideChar);
  1951. while LCharCount > 0 do
  1952. begin
  1953. LBytesPtr := PAnsiChar(@LBytes[0]);
  1954. LByteCount := SizeOf(LBytes);
  1955. //Kylix has an odd definition in iconv. In Kylix, __outbytesleft is defined as a var
  1956. //while in FreePascal's libc and our IdIconv units define it as a pSize_t
  1957. if iconv(FFromUTF16, @LCharsPtr, @LCharCount, @LBytesPtr, {$IFNDEF KYLIX}@{$ENDIF}LByteCount) = size_t(-1) then
  1958. begin
  1959. Result := 0;
  1960. Exit;
  1961. end;
  1962. // LByteCount was decremented by the number of bytes stored in the output buffer
  1963. Inc(Result, SizeOf(LBytes)-LByteCount);
  1964. end;
  1965. {$ELSE}
  1966. {$IFDEF WINDOWS}
  1967. Result := WideCharToMultiByte(FCodePage, FWCharToMBFlags, Chars, CharCount, nil, 0, nil, nil);
  1968. {$ELSE}
  1969. ToDo('GetByteCount() method of TIdMBCSEncoding class is not implemented for this platform yet'); {do not localize}
  1970. {$ENDIF}
  1971. {$ENDIF}
  1972. end;
  1973. function TIdMBCSEncoding.GetBytes(Chars: PWideChar; CharCount: Integer; Bytes: PByte;
  1974. ByteCount: Integer): Integer;
  1975. {$IFDEF USE_ICONV}
  1976. var
  1977. LCharsPtr, LBytesPtr: PAnsiChar;
  1978. LCharCount, LByteCount: size_t;
  1979. {$ENDIF}
  1980. begin
  1981. {$IFDEF USE_ICONV}
  1982. Result := 0;
  1983. LCharsPtr := PAnsiChar(Chars);
  1984. LCharCount := CharCount * SizeOf(WideChar);
  1985. LBytesPtr := PAnsiChar(Bytes);
  1986. LByteCount := ByteCount;
  1987. Assert (LBytesPtr <> nil,'TIdMBCSEncoding.GetBytes LBytesPtr can not be nil');
  1988. //Kylix has an odd definition in iconv. In Kylix, __outbytesleft is defined as a var
  1989. //while in FreePascal's libc and our IdIconv units define it as a pSize_t
  1990. if iconv(FFromUTF16, @LCharsPtr, @LCharCount, @LBytesPtr, {$IFNDEF KYLIX}@{$ENDIF}LByteCount) = size_t(-1) then
  1991. begin
  1992. Exit;
  1993. end;
  1994. // LByteCount was decremented by the number of bytes stored in the output buffer
  1995. Result := ByteCount-LByteCount;
  1996. {$ELSE}
  1997. {$IFDEF WINDOWS}
  1998. Result := WideCharToMultiByte(FCodePage, FWCharToMBFlags, Chars, CharCount, PAnsiChar(Bytes), ByteCount, nil, nil);
  1999. {$ELSE}
  2000. ToDo('GetBytes() method of TIdMBCSEncoding class is not implemented for this platform yet'); {do not localize}
  2001. {$ENDIF}
  2002. {$ENDIF}
  2003. end;
  2004. function TIdMBCSEncoding.GetCharCount(Bytes: PByte; ByteCount: Integer): Integer;
  2005. {$IFDEF USE_ICONV}
  2006. var
  2007. LChars: array[0..3] of WideChar;
  2008. LBytesPtr, LCharsPtr: PAnsiChar;
  2009. LByteCount, LCharsSize: size_t;
  2010. {$ENDIF}
  2011. begin
  2012. {$IFDEF USE_ICONV}
  2013. // RLebeau: iconv() does not allow for querying a pre-calculated character count
  2014. // for the input like Microsoft does, so have to determine the max characters
  2015. // by actually encoding the Ansi data to a real buffer. We'll encode to a
  2016. // small local buffer so we don't have to use a lot of memory...
  2017. Result := 0;
  2018. LBytesPtr := PAnsiChar(Bytes);
  2019. LByteCount := ByteCount;
  2020. while LByteCount > 0 do
  2021. begin
  2022. LCharsPtr := PAnsiChar(@LChars[0]);
  2023. LCharsSize := SizeOf(LChars);
  2024. //Kylix has an odd definition in iconv. In Kylix, __outbytesleft is defined as a var
  2025. //while in FreePascal's libc and our IdIconv units define it as a pSize_t
  2026. if iconv(FToUTF16, @LBytesPtr, @LByteCount, @LCharsPtr, {$IFNDEF KYLIX}@{$ENDIF}LCharsSize) = size_t(-1) then
  2027. begin
  2028. Result := 0;
  2029. Exit;
  2030. end;
  2031. // LBufferCount was decremented by the number of bytes stored in the output buffer
  2032. Inc(Result, (SizeOf(LChars)-LCharsSize) div SizeOf(WideChar));
  2033. end;
  2034. {$ELSE}
  2035. {$IFDEF WINDOWS}
  2036. Result := MultiByteToWideChar(FCodePage, FMBToWCharFlags, PAnsiChar(Bytes), ByteCount, nil, 0);
  2037. {$ELSE}
  2038. ToDo('GetCharCount() method of TIdMBCSEncoding class is not implemented for this platform yet'); {do not localize}
  2039. {$ENDIF}
  2040. {$ENDIF}
  2041. end;
  2042. function TIdMBCSEncoding.GetChars(Bytes: PByte; ByteCount: Integer; Chars: PWideChar;
  2043. CharCount: Integer): Integer;
  2044. {$IFDEF USE_ICONV}
  2045. var
  2046. LBytesPtr, LCharsPtr: PAnsiChar;
  2047. LByteCount, LCharsSize, LMaxCharsSize: size_t;
  2048. {$ENDIF}
  2049. begin
  2050. {$IFDEF USE_ICONV}
  2051. Result := 0;
  2052. LBytesPtr := PAnsiChar(Bytes);
  2053. LByteCount := ByteCount;
  2054. LCharsPtr := PAnsiChar(Chars);
  2055. LMaxCharsSize := CharCount * SizeOf(WideChar);
  2056. LCharsSize := LMaxCharsSize;
  2057. Assert (LCharsPtr <> nil,'TIdMBCSEncoding.GetChars LCharsPtr can not be nil');
  2058. //Kylix has an odd definition in iconv. In Kylix, __outbytesleft is defined as a var
  2059. //while in FreePascal's libc and our IdIconv units define it as a pSize_t
  2060. if iconv(FToUTF16, @LBytesPtr, @LByteCount, @LCharsPtr, {$IFNDEF KYLIX}@{$ENDIF}LCharsSize) = size_t(-1) then
  2061. begin
  2062. Exit;
  2063. end;
  2064. // LCharCount was decremented by the number of bytes stored in the output buffer
  2065. Inc(Result, (LMaxCharsSize-LCharsSize) div SizeOf(WideChar));
  2066. {$ELSE}
  2067. {$IFDEF WINDOWS}
  2068. Result := MultiByteToWideChar(FCodePage, FMBToWCharFlags, PAnsiChar(Bytes), ByteCount, Chars, CharCount);
  2069. {$ELSE}
  2070. ToDo('GetChars() method of TIdMBCSEncoding class is not implemented for this platform yet'); {do not localize}
  2071. {$ENDIF}
  2072. {$ENDIF}
  2073. end;
  2074. function TIdMBCSEncoding.GetMaxByteCount(CharCount: Integer): Integer;
  2075. begin
  2076. Result := (CharCount + 1) * FMaxCharSize;
  2077. end;
  2078. function TIdMBCSEncoding.GetMaxCharCount(ByteCount: Integer): Integer;
  2079. begin
  2080. Result := ByteCount;
  2081. end;
  2082. function TIdMBCSEncoding.GetPreamble: TIdBytes;
  2083. begin
  2084. {$IFDEF USE_ICONV}
  2085. case PosInStrArray(FCharSet, ['utf-8', 'utf-16', 'utf-16le', 'utf-16be'], False) of {do not localize}
  2086. 0: begin
  2087. SetLength(Result, 3);
  2088. Result[0] := $EF;
  2089. Result[1] := $BB;
  2090. Result[2] := $BF;
  2091. end;
  2092. 1, 2: begin
  2093. SetLength(Result, 2);
  2094. Result[0] := $FF;
  2095. Result[1] := $FE;
  2096. end;
  2097. 3: begin
  2098. SetLength(Result, 2);
  2099. Result[0] := $FE;
  2100. Result[1] := $FF;
  2101. end;
  2102. else
  2103. SetLength(Result, 0);
  2104. end;
  2105. {$ELSE}
  2106. {$IFDEF WINDOWS}
  2107. case FCodePage of
  2108. CP_UTF8: begin
  2109. SetLength(Result, 3);
  2110. Result[0] := $EF;
  2111. Result[1] := $BB;
  2112. Result[2] := $BF;
  2113. end;
  2114. 1200: begin
  2115. SetLength(Result, 2);
  2116. Result[0] := $FF;
  2117. Result[1] := $FE;
  2118. end;
  2119. 1201: begin
  2120. SetLength(Result, 2);
  2121. Result[0] := $FE;
  2122. Result[1] := $FF;
  2123. end;
  2124. else
  2125. SetLength(Result, 0);
  2126. end;
  2127. {$ELSE}
  2128. SetLength(Result, 0);
  2129. ToDo('GetPreamble() method of TIdMBCSEncoding class is not implemented for this platform yet'); {do not localize}
  2130. {$ENDIF}
  2131. {$ENDIF}
  2132. end;
  2133. { TIdUTF7Encoding }
  2134. constructor TIdUTF7Encoding.Create;
  2135. begin
  2136. {$IFDEF USE_ICONV}
  2137. inherited Create('UTF-7');
  2138. {$ELSE}
  2139. {$IFDEF WINDOWS}
  2140. inherited Create(CP_UTF7);
  2141. {$ELSE}
  2142. ToDo('Construtor of TIdUTF7Encoding class is not implemented for this platform yet'); {do not localize}
  2143. {$ENDIF}
  2144. {$ENDIF}
  2145. end;
  2146. function TIdUTF7Encoding.GetByteCount(Chars: PWideChar; CharCount: Integer): Integer;
  2147. begin
  2148. Result := inherited GetByteCount(Chars, CharCount);
  2149. end;
  2150. function TIdUTF7Encoding.GetBytes(Chars: PWideChar; CharCount: Integer; Bytes: PByte;
  2151. ByteCount: Integer): Integer;
  2152. begin
  2153. Result := inherited GetBytes(Chars, CharCount, Bytes, ByteCount);
  2154. end;
  2155. function TIdUTF7Encoding.GetCharCount(Bytes: PByte; ByteCount: Integer): Integer;
  2156. begin
  2157. Result := inherited GetCharCount(Bytes, ByteCount);
  2158. end;
  2159. function TIdUTF7Encoding.GetChars(Bytes: PByte; ByteCount: Integer; Chars: PWideChar;
  2160. CharCount: Integer): Integer;
  2161. begin
  2162. Result := inherited GetChars(Bytes, ByteCount, Chars, CharCount);
  2163. end;
  2164. function TIdUTF7Encoding.GetMaxByteCount(CharCount: Integer): Integer;
  2165. begin
  2166. Result := (CharCount * 3) + 2;
  2167. end;
  2168. function TIdUTF7Encoding.GetMaxCharCount(ByteCount: Integer): Integer;
  2169. begin
  2170. Result := ByteCount;
  2171. end;
  2172. { TIdUTF8Encoding }
  2173. constructor TIdUTF8Encoding.Create;
  2174. begin
  2175. {$IFDEF USE_ICONV}
  2176. inherited Create('UTF-8');
  2177. {$ELSE}
  2178. {$IFDEF WINDOWS}
  2179. inherited Create(CP_UTF8, 0, 0);
  2180. {$ELSE}
  2181. ToDo('Constructor of TIdUTF8Encoding class is not implemented for this platform yet'); {do not localize}
  2182. {$ENDIF}
  2183. {$ENDIF}
  2184. end;
  2185. function TIdUTF8Encoding.GetMaxByteCount(CharCount: Integer): Integer;
  2186. begin
  2187. Result := (CharCount + 1) * 3;
  2188. end;
  2189. function TIdUTF8Encoding.GetMaxCharCount(ByteCount: Integer): Integer;
  2190. begin
  2191. Result := ByteCount + 1;
  2192. end;
  2193. function TIdUTF8Encoding.GetPreamble: TIdBytes;
  2194. begin
  2195. SetLength(Result, 3);
  2196. Result[0] := $EF;
  2197. Result[1] := $BB;
  2198. Result[2] := $BF;
  2199. end;
  2200. { TIdUTF16LittleEndianEncoding }
  2201. constructor TIdUTF16LittleEndianEncoding.Create;
  2202. begin
  2203. FIsSingleByte := False;
  2204. FMaxCharSize := 4;
  2205. end;
  2206. function TIdUTF16LittleEndianEncoding.GetByteCount(Chars: PWideChar; CharCount: Integer): Integer;
  2207. begin
  2208. Result := CharCount * SizeOf(WideChar);
  2209. end;
  2210. function TIdUTF16LittleEndianEncoding.GetBytes(Chars: PWideChar; CharCount: Integer;
  2211. Bytes: PByte; ByteCount: Integer): Integer;
  2212. {$IFDEF ENDIAN_BIG}
  2213. var
  2214. I: Integer;
  2215. {$ENDIF}
  2216. begin
  2217. {$IFDEF ENDIAN_BIG}
  2218. for I := CharCount - 1 downto 0 do
  2219. begin
  2220. Bytes^ := Hi(Word(Chars^));
  2221. Inc(Bytes);
  2222. Bytes^ := Lo(Word(Chars^));
  2223. Inc(Bytes);
  2224. Inc(Chars);
  2225. end;
  2226. Result := CharCount * SizeOf(WideChar);
  2227. {$ELSE}
  2228. Result := CharCount * SizeOf(WideChar);
  2229. Move(Chars^, Bytes^, Result);
  2230. {$ENDIF}
  2231. end;
  2232. function TIdUTF16LittleEndianEncoding.GetCharCount(Bytes: PByte; ByteCount: Integer): Integer;
  2233. begin
  2234. Result := ByteCount div SizeOf(WideChar);
  2235. end;
  2236. function TIdUTF16LittleEndianEncoding.GetChars(Bytes: PByte; ByteCount: Integer;
  2237. Chars: PWideChar; CharCount: Integer): Integer;
  2238. {$IFDEF ENDIAN_BIG}
  2239. var
  2240. P: PByte;
  2241. I: Integer;
  2242. {$ENDIF}
  2243. begin
  2244. {$IFDEF ENDIAN_BIG}
  2245. P := Bytes;
  2246. Inc(P);
  2247. for I := 0 to CharCount - 1 do
  2248. begin
  2249. Chars^ := WideChar(MakeWord(P^, Bytes^));
  2250. Inc(Bytes, 2);
  2251. Inc(P, 2);
  2252. Inc(Chars);
  2253. end;
  2254. Result := CharCount;
  2255. {$ELSE}
  2256. Result := ByteCount div SizeOf(WideChar);
  2257. Move(Bytes^, Chars^, Result * SizeOf(WideChar));
  2258. {$ENDIF}
  2259. end;
  2260. function TIdUTF16LittleEndianEncoding.GetMaxByteCount(CharCount: Integer): Integer;
  2261. begin
  2262. Result := (CharCount + 1) * 2;
  2263. end;
  2264. function TIdUTF16LittleEndianEncoding.GetMaxCharCount(ByteCount: Integer): Integer;
  2265. begin
  2266. Result := (ByteCount div SizeOf(WideChar)) + (ByteCount and 1) + 1;
  2267. end;
  2268. function TIdUTF16LittleEndianEncoding.GetPreamble: TIdBytes;
  2269. begin
  2270. SetLength(Result, 2);
  2271. Result[0] := $FF;
  2272. Result[1] := $FE;
  2273. end;
  2274. { TIdUTF16BigEndianEncoding }
  2275. function TIdUTF16BigEndianEncoding.GetBytes(Chars: PWideChar; CharCount: Integer;
  2276. Bytes: PByte; ByteCount: Integer): Integer;
  2277. {$IFDEF ENDIAN_LITTLE}
  2278. var
  2279. I: Integer;
  2280. {$ENDIF}
  2281. begin
  2282. {$IFDEF ENDIAN_LITTLE}
  2283. for I := CharCount - 1 downto 0 do
  2284. begin
  2285. Bytes^ := Hi(Word(Chars^));
  2286. Inc(Bytes);
  2287. Bytes^ := Lo(Word(Chars^));
  2288. Inc(Bytes);
  2289. Inc(Chars);
  2290. end;
  2291. Result := CharCount * SizeOf(WideChar);
  2292. {$ELSE}
  2293. Result := CharCount * SizeOf(WideChar);
  2294. Move(Chars^, Bytes^, Result);
  2295. {$ENDIF}
  2296. end;
  2297. function TIdUTF16BigEndianEncoding.GetChars(Bytes: PByte; ByteCount: Integer;
  2298. Chars: PWideChar; CharCount: Integer): Integer;
  2299. {$IFDEF ENDIAN_LITTLE}
  2300. var
  2301. P: PByte;
  2302. I: Integer;
  2303. {$ENDIF}
  2304. begin
  2305. {$IFDEF ENDIAN_LITTLE}
  2306. P := Bytes;
  2307. Inc(P);
  2308. for I := 0 to CharCount - 1 do
  2309. begin
  2310. Chars^ := WideChar(MakeWord(P^, Bytes^));
  2311. Inc(Bytes, 2);
  2312. Inc(P, 2);
  2313. Inc(Chars);
  2314. end;
  2315. Result := CharCount;
  2316. {$ELSE}
  2317. Result := ByteCount div SizeOf(WideChar);
  2318. Move(Bytes^, Chars^, Result * SizeOf(WideChar));
  2319. {$ENDIF}
  2320. end;
  2321. function TIdUTF16BigEndianEncoding.GetPreamble: TIdBytes;
  2322. begin
  2323. SetLength(Result, 2);
  2324. Result[0] := $FE;
  2325. Result[1] := $FF;
  2326. end;
  2327. {$ENDIF} // end of {$IFNDEF TIdTextEncoding_IS_NATIVE}
  2328. function enDefault: TIdTextEncoding;
  2329. {$IFDEF USE_INLINE}inline;{$ENDIF}
  2330. begin
  2331. Result := nil;
  2332. end;
  2333. function en7Bit: TIdTextEncoding;
  2334. {$IFDEF USE_INLINE}inline;{$ENDIF}
  2335. begin
  2336. Result := IndyASCIIEncoding;
  2337. end;
  2338. function en8Bit: TIdTextEncoding;
  2339. {$IFDEF USE_INLINE}inline;{$ENDIF}
  2340. begin
  2341. Result := Indy8BitEncoding;
  2342. end;
  2343. function enUTF8: TIdTextEncoding;
  2344. {$IFDEF USE_INLINE}inline;{$ENDIF}
  2345. begin
  2346. Result := IndyUTF8Encoding;
  2347. end;
  2348. {$IFDEF DOTNET}
  2349. function Indy8BitEncoding: TIdTextEncoding;
  2350. {$IFDEF USE_INLINE}inline;{$ENDIF}
  2351. begin
  2352. // We need a charset that converts UTF-16 codeunits in the $00-$FF range
  2353. // to/from their numeric values as-is. Was previously using "Windows-1252"
  2354. // which does so for most codeunits, however codeunits $80-$9F in
  2355. // Windows-1252 map to different codepoints in Unicode, which we don't want.
  2356. // "ISO-8859-1" aka "ISO_8859-1:1987" (not to be confused with the older
  2357. // "ISO 8859-1" charset), on the other hand, treats codeunits $00-$FF as-is,
  2358. // and seems to be just as widely supported as Windows-1252 on most systems,
  2359. // so we'll use that for now...
  2360. Result := TIdTextEncoding.GetEncoding('ISO-8859-1');
  2361. end;
  2362. function IndyASCIIEncoding: TIdTextEncoding;
  2363. {$IFDEF USE_INLINE}inline;{$ENDIF}
  2364. begin
  2365. Result := TIdTextEncoding.ASCII;
  2366. end;
  2367. function IndyUTF8Encoding: TIdTextEncoding;
  2368. {$IFDEF USE_INLINE}inline;{$ENDIF}
  2369. begin
  2370. Result := TIdTextEncoding.UTF8;
  2371. end;
  2372. {$ELSE}
  2373. { TIdASCIIEncoding }
  2374. constructor TIdASCIIEncoding.Create;
  2375. begin
  2376. FIsSingleByte := True;
  2377. FMaxCharSize := 1;
  2378. end;
  2379. function TIdASCIIEncoding.GetByteCount(AChars: PIdWideChar; ACharCount: Integer): Integer;
  2380. begin
  2381. Result := ACharCount;
  2382. end;
  2383. function TIdASCIIEncoding.GetBytes(AChars: PIdWideChar; ACharCount: Integer;
  2384. ABytes: PByte; AByteCount: Integer): Integer;
  2385. var
  2386. i : Integer;
  2387. begin
  2388. Result := IndyMin(ACharCount, AByteCount);
  2389. for i := 1 to Result do begin
  2390. // replace illegal characters > $7F
  2391. if Word(AChars^) > $007F then begin
  2392. ABytes^ := Byte(Ord('?'));
  2393. end else begin
  2394. ABytes^ := Byte(AChars^);
  2395. end;
  2396. //advance to next char
  2397. Inc(AChars);
  2398. Inc(ABytes);
  2399. end;
  2400. end;
  2401. function TIdASCIIEncoding.GetCharCount(ABytes: PByte; AByteCount: Integer): Integer;
  2402. begin
  2403. Result := AByteCount;
  2404. end;
  2405. function TIdASCIIEncoding.GetChars(ABytes: PByte; AByteCount: Integer;
  2406. AChars: PIdWideChar; ACharCount: Integer): Integer;
  2407. var
  2408. i : Integer;
  2409. begin
  2410. Result := IndyMin(ACharCount, AByteCount);
  2411. for i := 1 to Result do begin
  2412. // This is an invalid byte in the ASCII encoding.
  2413. if ABytes^ > $7F then begin
  2414. Word(AChars^) := Ord('?');
  2415. end else begin
  2416. Word(AChars^) := ABytes^;
  2417. end;
  2418. //advance to next byte
  2419. Inc(AChars);
  2420. Inc(ABytes);
  2421. end;
  2422. end;
  2423. function TIdASCIIEncoding.GetMaxByteCount(ACharCount: Integer): Integer;
  2424. begin
  2425. Result := ACharCount;
  2426. end;
  2427. function TIdASCIIEncoding.GetMaxCharCount(AByteCount: Integer): Integer;
  2428. begin
  2429. Result := AByteCount;
  2430. end;
  2431. function TIdASCIIEncoding.GetPreamble: TIdBytes;
  2432. begin
  2433. SetLength(Result, 0);
  2434. end;
  2435. function IndyASCIIEncoding(const AOwnedByIndy: Boolean = True): TIdTextEncoding;
  2436. var
  2437. LEncoding: TIdTextEncoding;
  2438. begin
  2439. if not AOwnedByIndy then begin
  2440. LEncoding := TIdASCIIEncoding.Create;
  2441. end else
  2442. begin
  2443. if GIdASCIIEncoding = nil then begin
  2444. LEncoding := TIdASCIIEncoding.Create;
  2445. if InterlockedCompareExchangePtr(Pointer(GIdASCIIEncoding), LEncoding, nil) <> nil then begin
  2446. LEncoding.Free;
  2447. end;
  2448. end;
  2449. LEncoding := GIdASCIIEncoding;
  2450. end;
  2451. Result := LEncoding;
  2452. end;
  2453. { TId8BitEncoding }
  2454. type
  2455. TId8BitEncoding = class(TIdTextEncoding)
  2456. protected
  2457. function GetByteCount(AChars: PIdWideChar; ACharCount: Integer): Integer; override;
  2458. function GetBytes(AChars: PIdWideChar; ACharCount: Integer; ABytes: PByte; AByteCount: Integer): Integer; override;
  2459. function GetCharCount(ABytes: PByte; AByteCount: Integer): Integer; override;
  2460. function GetChars(ABytes: PByte; AByteCount: Integer; AChars: PIdWideChar; ACharCount: Integer): Integer; override;
  2461. public
  2462. constructor Create; virtual;
  2463. function GetMaxByteCount(ACharCount: Integer): Integer; override;
  2464. function GetMaxCharCount(AByteCount: Integer): Integer; override;
  2465. function GetPreamble: TIdBytes; override;
  2466. end;
  2467. constructor TId8BitEncoding.Create;
  2468. begin
  2469. FIsSingleByte := True;
  2470. FMaxCharSize := 1;
  2471. end;
  2472. function TId8BitEncoding.GetByteCount(AChars: PIdWideChar; ACharCount: Integer): Integer;
  2473. begin
  2474. Result := ACharCount;
  2475. end;
  2476. function TId8BitEncoding.GetBytes(AChars: PIdWideChar; ACharCount: Integer;
  2477. ABytes: PByte; AByteCount: Integer): Integer;
  2478. var
  2479. i : Integer;
  2480. begin
  2481. Result := IndyMin(ACharCount, AByteCount);
  2482. for i := 1 to Result do begin
  2483. // replace illegal characters > $FF
  2484. if Word(AChars^) > $00FF then begin
  2485. ABytes^ := Byte(Ord('?'));
  2486. end else begin
  2487. ABytes^ := Byte(AChars^);
  2488. end;
  2489. //advance to next char
  2490. Inc(AChars);
  2491. Inc(ABytes);
  2492. end;
  2493. end;
  2494. function TId8BitEncoding.GetCharCount(ABytes: PByte; AByteCount: Integer): Integer;
  2495. begin
  2496. Result := AByteCount;
  2497. end;
  2498. function TId8BitEncoding.GetChars(ABytes: PByte; AByteCount: Integer;
  2499. AChars: PIdWideChar; ACharCount: Integer): Integer;
  2500. var
  2501. i : Integer;
  2502. begin
  2503. Result := IndyMin(ACharCount, AByteCount);
  2504. for i := 1 to Result do begin
  2505. Word(AChars^) := ABytes^;
  2506. //advance to next char
  2507. Inc(AChars);
  2508. Inc(ABytes);
  2509. end;
  2510. end;
  2511. function TId8BitEncoding.GetMaxByteCount(ACharCount: Integer): Integer;
  2512. begin
  2513. Result := ACharCount;
  2514. end;
  2515. function TId8BitEncoding.GetMaxCharCount(AByteCount: Integer): Integer;
  2516. begin
  2517. Result := AByteCount;
  2518. end;
  2519. function TId8BitEncoding.GetPreamble: TIdBytes;
  2520. begin
  2521. SetLength(Result, 0);
  2522. end;
  2523. function Indy8BitEncoding(const AOwnedByIndy: Boolean = True): TIdTextEncoding;
  2524. var
  2525. LEncoding: TIdTextEncoding;
  2526. begin
  2527. if not AOwnedByIndy then begin
  2528. LEncoding := TId8BitEncoding.Create;
  2529. end else
  2530. begin
  2531. if GId8BitEncoding = nil then begin
  2532. LEncoding := TId8BitEncoding.Create;
  2533. if InterlockedCompareExchangePtr(Pointer(GId8BitEncoding), LEncoding, nil) <> nil then begin
  2534. LEncoding.Free;
  2535. end;
  2536. end;
  2537. LEncoding := GId8BitEncoding;
  2538. end;
  2539. Result := LEncoding;
  2540. end;
  2541. // TODO: implement a custom TIdUTF8Encoding class so we don't have to
  2542. // deal with codepage issues...
  2543. function IndyUTF8Encoding(const AOwnedByIndy: Boolean = True): TIdTextEncoding;
  2544. var
  2545. LEncoding: TIdTextEncoding;
  2546. function CreateUTF8Encoding: TIdTextEncoding;
  2547. begin
  2548. {$IFDEF USE_ICONV}
  2549. Result := TIdMBCSEncoding.Create('UTF-8');
  2550. {$ELSE}
  2551. {$IFDEF WINDOWS}
  2552. // RLebeau: SysUtils.TUTF8Encoding uses the MB_ERR_INVALID_CHARS
  2553. // flag by default, which we do not want to use, so calling the
  2554. // overloaded constructor that lets us override that behavior...
  2555. Result := TIdUTF8Encoding.Create(CP_UTF8, 0, 0);
  2556. {$ELSE}
  2557. {$IFDEF USE_VCL_POSIX}
  2558. Result := TIdUTF8Encoding.Create;
  2559. {$ELSE}
  2560. Result := nil;
  2561. ToDo('IndyUTF8Encoding() is not implemented for this platform yet'); {do not localize}
  2562. {$ENDIF}
  2563. {$ENDIF}
  2564. {$ENDIF}
  2565. end;
  2566. begin
  2567. if not AOwnedByIndy then begin
  2568. LEncoding := CreateUTF8Encoding;
  2569. end else
  2570. begin
  2571. if GIdUTF8Encoding = nil then begin
  2572. LEncoding := CreateUTF8Encoding;
  2573. if InterlockedCompareExchangePtr(Pointer(GIdUTF8Encoding), LEncoding, nil) <> nil then begin
  2574. LEncoding.Free;
  2575. end;
  2576. end;
  2577. LEncoding := GIdUTF8Encoding;
  2578. end;
  2579. Result := LEncoding;
  2580. end;
  2581. {$ENDIF}
  2582. {$IFDEF UNIX}
  2583. function HackLoadFileName(const ALibName, ALibVer : String) : string; {$IFDEF USE_INLINE} inline; {$ENDIF}
  2584. begin
  2585. {$IFDEF DARWIN}
  2586. Result := ALibName+ALibVer+LIBEXT;
  2587. {$ELSE}
  2588. Result := ALibName+LIBEXT+ALibVer;
  2589. {$ENDIF}
  2590. end;
  2591. function HackLoad(const ALibName : String; const ALibVersions : array of String) : HMODULE;
  2592. var
  2593. i : Integer;
  2594. begin
  2595. Result := NilHandle;
  2596. for i := Low(ALibVersions) to High(ALibVersions) do
  2597. begin
  2598. {$IFDEF USE_SAFELOADLIBRARY}
  2599. Result := SafeLoadLibrary(HackLoadFileName(ALibName,ALibVersions[i]));
  2600. {$ELSE}
  2601. {$IFDEF KYLIXCOMPAT}
  2602. // Workaround that is required under Linux (changed RTLD_GLOBAL with RTLD_LAZY Note: also work with LoadLibrary())
  2603. Result := HMODULE(dlopen(PAnsiChar(HackLoadFileName(ALibName,ALibVersions[i])), RTLD_LAZY));
  2604. {$ELSE}
  2605. Result := LoadLibrary(HackLoadFileName(ALibName,ALibVersions[i]));
  2606. {$ENDIF}
  2607. {$ENDIF}
  2608. {$IFDEF USE_INVALIDATE_MOD_CACHE}
  2609. InvalidateModuleCache;
  2610. {$ENDIF}
  2611. if Result <> NilHandle then begin
  2612. break;
  2613. end;
  2614. end;
  2615. end;
  2616. {$ENDIF}
  2617. procedure IndyRaiseLastError;
  2618. {$IFDEF USE_INLINE}inline;{$ENDIF}
  2619. begin
  2620. {$IFNDEF HAS_RaiseLastOSError}
  2621. RaiseLastWin32Error;
  2622. {$ELSE}
  2623. RaiseLastOSError;
  2624. {$ENDIF}
  2625. end;
  2626. {$IFNDEF DOTNET}
  2627. function InterlockedExchangeTHandle(var VTarget: THandle; const AValue: THandle): THandle;
  2628. {$IFDEF USE_INLINE}inline;{$ENDIF}
  2629. begin
  2630. {$IFDEF HAS_TInterlocked}
  2631. {$IFDEF THANDLE_32}
  2632. Result := THandle(TInterlocked.Exchange(LongInt(VTarget), LongInt(AValue)));
  2633. {$ENDIF}
  2634. //Temporary workaround. TInterlocked for Emb really should accept 64 bit unsigned values as set of parameters
  2635. //for TInterlocked.Exchange since 64-bit wide integers are common on 64 bit platforms.
  2636. {$IFDEF THANDLE_64}
  2637. Result := THandle(TInterlocked.Exchange(Int64(VTarget), Int64(AValue)));
  2638. {$ENDIF}
  2639. {$ELSE}
  2640. {$IFDEF THANDLE_32}
  2641. Result := THandle(InterlockedExchange(LongInt(VTarget), LongInt(AValue)));
  2642. {$ENDIF}
  2643. {$IFDEF THANDLE_64}
  2644. Result := THandle(InterlockedExchange64(Int64(VTarget), Int64(AValue)));
  2645. {$ENDIF}
  2646. {$ENDIF}
  2647. end;
  2648. {$UNDEF DYNAMICLOAD_InterlockedCompareExchange}
  2649. {$IFNDEF HAS_TInterlocked}
  2650. {$IFNDEF FPC}
  2651. // RLebeau: InterlockedCompareExchange() is not available prior to Win2K,
  2652. // so need to fallback to some other logic on older systems. Not too many
  2653. // people still support those systems anymore, so we will make this optional.
  2654. //
  2655. // InterlockedCompareExchange64(), on the other hand, is not available until
  2656. // Windows Vista (and not defined in any version of Windows.pas up to Delphi
  2657. // XE), so always dynamically load it in order to support WinXP 64-bit...
  2658. {$IFDEF CPU64}
  2659. {$DEFINE DYNAMICLOAD_InterlockedCompareExchange}
  2660. {$ELSE}
  2661. {.$DEFINE STATICLOAD_InterlockedCompareExchange}
  2662. {$ENDIF}
  2663. {$ENDIF}
  2664. {$ENDIF}
  2665. {$IFDEF DYNAMICLOAD_InterlockedCompareExchange}
  2666. // See http://code.google.com/p/delphi-toolbox/source/browse/trunk/RTLEx/RTLEx.BasicOp.Atomic.pas
  2667. // for how to perform interlocked operations in assembler...
  2668. type
  2669. TInterlockedCompareExchangeFunc = function(var Destination: PtrInt; Exchange, Comparand: PtrInt): PtrInt; stdcall;
  2670. var
  2671. InterlockedCompareExchange: TInterlockedCompareExchangeFunc = nil;
  2672. function Impl_InterlockedCompareExchange(var Destination: PtrInt; Exchange, Comparand: PtrInt): LongInt; stdcall;
  2673. {$IFDEF USE_INLINE}inline;{$ENDIF}
  2674. begin
  2675. {$IFDEF CPU64}
  2676. // TODO: use LOCK CMPXCHG8B directly so this is more atomic...
  2677. end;
  2678. {$ELSE}
  2679. // TODO: use LOCK CMPXCHG directly so this is more atomic...
  2680. {$ENDIF}
  2681. Result := Destination;
  2682. if Destination = Comparand then begin
  2683. Destination := Exchange;
  2684. end;
  2685. end;
  2686. function Stub_InterlockedCompareExchange(var Destination: PtrInt; Exchange, Comparand: PtrInt): PtrInt; stdcall;
  2687. function GetImpl: Pointer;
  2688. const
  2689. cKernel32 = 'KERNEL32'; {do not localize}
  2690. // TODO: what is Embarcadero's 64-bit define going to be?
  2691. cInterlockedCompareExchange = {$IFDEF CPU64}'InterlockedCompareExchange64'{$ELSE}'InterlockedCompareExchange'{$ENDIF}; {do not localize}
  2692. begin
  2693. Result := GetProcAddress(GetModuleHandle(cKernel32), cInterlockedCompareExchange);
  2694. if Result = nil then begin
  2695. Result := @Impl_InterlockedCompareExchange;
  2696. end;
  2697. end;
  2698. begin
  2699. @InterlockedCompareExchange := GetImpl();
  2700. Result := InterlockedCompareExchange(Destination, Exchange, Comparand);
  2701. end;
  2702. {$ENDIF}
  2703. function InterlockedCompareExchangePtr(var VTarget: Pointer; const AValue, Compare: Pointer): Pointer;
  2704. {$IFNDEF DYNAMICLOAD_InterlockedCompareExchange}
  2705. {$IFDEF USE_INLINE}inline;{$ENDIF}
  2706. {$ENDIF}
  2707. begin
  2708. {$IFDEF DYNAMICLOAD_InterlockedCompareExchange}
  2709. Result := Pointer(IdGlobal.InterlockedCompareExchange(PtrInt(VTarget), PtrInt(AValue), PtrInt(Compare)));
  2710. {$ELSE}
  2711. {$IFDEF HAS_TInterlocked}
  2712. Result := TInterlocked.CompareExchange(VTarget, AValue, Compare);
  2713. {$ELSE}
  2714. {$IFDEF HAS_InterlockedCompareExchangePointer}
  2715. Result := InterlockedCompareExchangePointer(VTarget, AValue, Compare);
  2716. {$ELSE}
  2717. {$IFDEF HAS_InterlockedCompareExchange_Pointers}
  2718. //work around a conflicting definition for InterlockedCompareExchange
  2719. Result := {$IFDEF FPC}system.{$ENDIF}InterlockedCompareExchange(VTarget, AValue, Compare);
  2720. {$ELSE}
  2721. {$IFDEF FPC}
  2722. Result := Pointer(
  2723. {$IFDEF CPU64}InterlockedCompareExchange64{$ELSE}InterlockedCompareExchange{$ENDIF}
  2724. (PtrInt(VTarget), PtrInt(AValue), PtrInt(Compare))
  2725. );
  2726. {$ELSE}
  2727. // Delphi 64-bit is handled by HAS_InterlockedCompareExchangePointer
  2728. Result := Pointer(InterlockedCompareExchange(Longint(VTarget), Longint(AValue), Longint(Compare)));
  2729. {$ENDIF}
  2730. {$ENDIF}
  2731. {$ENDIF}
  2732. {$ENDIF}
  2733. {$ENDIF}
  2734. end;
  2735. {$ENDIF}
  2736. {Little Endian Byte order functions from:
  2737. From: http://community.borland.com/article/0,1410,16854,00.html
  2738. Big-endian and little-endian formated integers - by Borland Developer Support Staff
  2739. Note that I will NOT do big Endian functions because the stacks can handle that
  2740. with HostToNetwork and NetworkToHost functions.
  2741. You should use these functions for writing data that sent and received in Little
  2742. Endian Form. Do NOT assume endianness of what's written. It can work in unpredictable
  2743. ways on other architectures.
  2744. }
  2745. function HostToLittleEndian(const AValue : Word) : Word;
  2746. {$IFDEF USE_INLINE}inline;{$ENDIF}
  2747. begin
  2748. {$IFDEF DOTNET}
  2749. //I think that is Little Endian but I'm not completely sure
  2750. Result := AValue;
  2751. {$ELSE}
  2752. {$IFDEF ENDIAN_LITTLE}
  2753. Result := AValue;
  2754. {$ENDIF}
  2755. {$IFDEF ENDIAN_BIG}
  2756. Result := swap(AValue);
  2757. {$ENDIF}
  2758. {$ENDIF}
  2759. end;
  2760. function HostToLittleEndian(const AValue : LongWord) : LongWord;
  2761. {$IFDEF USE_INLINE}inline;{$ENDIF}
  2762. begin
  2763. {$IFDEF DOTNET}
  2764. //I think that is Little Endian but I'm not completely sure
  2765. Result := AValue;
  2766. {$ELSE}
  2767. {$IFDEF ENDIAN_LITTLE}
  2768. Result := AValue;
  2769. {$ENDIF}
  2770. {$IFDEF ENDIAN_BIG}
  2771. Result := swap(AValue shr 16) or (Longint(swap(AValue and $FFFF)) shl 16);
  2772. {$ENDIF}
  2773. {$ENDIF}
  2774. end;
  2775. function HostToLittleEndian(const AValue : Integer) : Integer;
  2776. {$IFDEF USE_INLINE}inline;{$ENDIF}
  2777. begin
  2778. {$IFDEF DOTNET}
  2779. //I think that is Little Endian but I'm not completely sure
  2780. Result := AValue;
  2781. {$ELSE}
  2782. {$IFDEF ENDIAN_LITTLE}
  2783. Result := AValue;
  2784. {$ENDIF}
  2785. {$IFDEF ENDIAN_BIG}
  2786. Result := swap(AValue);
  2787. {$ENDIF}
  2788. {$ENDIF}
  2789. end;
  2790. function LittleEndianToHost(const AValue : Word) : Word;
  2791. {$IFDEF USE_INLINE}inline;{$ENDIF}
  2792. begin
  2793. {$IFDEF DOTNET}
  2794. //I think that is Little Endian but I'm not completely sure
  2795. Result := AValue;
  2796. {$ELSE}
  2797. {$IFDEF ENDIAN_LITTLE}
  2798. Result := AValue;
  2799. {$ENDIF}
  2800. {$IFDEF ENDIAN_BIG}
  2801. Result := swap(AValue);
  2802. {$ENDIF}
  2803. {$ENDIF}
  2804. end;
  2805. function LittleEndianToHost(const AValue : Longword): Longword;
  2806. {$IFDEF USE_INLINE}inline;{$ENDIF}
  2807. begin
  2808. {$IFDEF DOTNET}
  2809. //I think that is Little ENdian but I'm not completely sure
  2810. Result := AValue;
  2811. {$ELSE}
  2812. {$IFDEF ENDIAN_LITTLE}
  2813. Result := AValue;
  2814. {$ENDIF}
  2815. {$IFDEF ENDIAN_BIG}
  2816. Result := swap(AValue shr 16) or (Longint(swap(AValue and $FFFF)) shl 16);
  2817. {$ENDIF}
  2818. {$ENDIF}
  2819. end;
  2820. function LittleEndianToHost(const AValue : Integer): Integer;
  2821. {$IFDEF USE_INLINE}inline;{$ENDIF}
  2822. begin
  2823. {$IFDEF DOTNET}
  2824. //I think that is Little ENdian but I'm not completely sure
  2825. Result := AValue;
  2826. {$ELSE}
  2827. {$IFDEF ENDIAN_LITTLE}
  2828. Result := AValue;
  2829. {$ENDIF}
  2830. {$IFDEF ENDIAN_BIG}
  2831. Result := Swap(AValue);
  2832. {$ENDIF}
  2833. {$ENDIF}
  2834. end;
  2835. // TODO: add an AIndex parameter
  2836. procedure FillBytes(var VBytes : TIdBytes; const ACount : Integer; const AValue : Byte);
  2837. {$IFDEF STRING_IS_ANSI}
  2838. {$IFDEF USE_INLINE}inline;{$ENDIF}
  2839. {$ELSE}
  2840. var
  2841. I: Integer;
  2842. {$ENDIF}
  2843. begin
  2844. // RLebeau: FillChar() is bad to use on Delphi/C++Builder 2009+ for filling
  2845. // byte buffers as it is actually designed for filling character buffers
  2846. // instead. Now that Char maps to WideChar, this causes problems for FillChar().
  2847. {$IFDEF STRING_IS_UNICODE}
  2848. //System.&Array.Clear(VBytes, 0, ACount);
  2849. // TODO: optimize this
  2850. for I := 0 to ACount-1 do begin
  2851. VBytes[I] := AValue;
  2852. end;
  2853. {$ELSE}
  2854. FillChar(VBytes[0], ACount, AValue);
  2855. {$ENDIF}
  2856. end;
  2857. constructor TIdFileCreateStream.Create(const AFile : String);
  2858. begin
  2859. inherited Create(AFile, fmCreate);
  2860. end;
  2861. constructor TIdAppendFileStream.Create(const AFile : String);
  2862. var
  2863. LFlags: Word;
  2864. begin
  2865. if FileExists(AFile) then begin
  2866. LFlags := fmOpenReadWrite or fmShareDenyWrite;
  2867. end else begin
  2868. LFlags := fmCreate;
  2869. end;
  2870. inherited Create(AFile, LFlags);
  2871. if LFlags <> fmCreate then begin
  2872. TIdStreamHelper.Seek(Self, 0, soEnd);
  2873. end;
  2874. end;
  2875. constructor TIdReadFileNonExclusiveStream.Create(const AFile : String);
  2876. begin
  2877. inherited Create(AFile, fmOpenRead or fmShareDenyNone);
  2878. end;
  2879. constructor TIdReadFileExclusiveStream.Create(const AFile : String);
  2880. begin
  2881. inherited Create(AFile, fmOpenRead or fmShareDenyWrite);
  2882. end;
  2883. function IsASCIILDH(const AByte: Byte): Boolean;
  2884. {$IFDEF USE_INLINE}inline;{$ENDIF}
  2885. begin
  2886. Result := True;
  2887. //Verify the absence of non-LDH ASCII code points; that is, the
  2888. //absence of 0..2C, 2E..2F, 3A..40, 5B..60, and 7B..7F.
  2889. //Permissable chars are in this set
  2890. //['-','0'..'9','A'..'Z','a'..'z']
  2891. if AByte <= $2C then begin
  2892. Result := False;
  2893. end
  2894. else if (AByte >= $2E) and (AByte <= $2F) then begin
  2895. Result := False;
  2896. end
  2897. else if (AByte >= $3A) and (AByte <= $40) then begin
  2898. Result := False;
  2899. end
  2900. else if (AByte >= $5B) and (AByte <= $60) then begin
  2901. Result := False;
  2902. end
  2903. else if (AByte >= $7B) and (AByte <= $7F) then begin
  2904. Result := False;
  2905. end;
  2906. end;
  2907. function IsASCIILDH(const ABytes: TIdBytes): Boolean;
  2908. var
  2909. i: Integer;
  2910. begin
  2911. for i := 0 to Length(ABytes)-1 do begin
  2912. if not IsASCIILDH(ABytes[i]) then
  2913. begin
  2914. Result := False;
  2915. Exit;
  2916. end;
  2917. end;
  2918. Result := True;
  2919. end;
  2920. function IsASCII(const AByte: Byte): Boolean;
  2921. {$IFDEF USE_INLINE}inline;{$ENDIF}
  2922. begin
  2923. Result := AByte <= $7F;
  2924. end;
  2925. function IsASCII(const ABytes: TIdBytes): Boolean;
  2926. var
  2927. i: Integer;
  2928. begin
  2929. for i := 0 to Length(ABytes) -1 do begin
  2930. if not IsASCII(ABytes[i]) then begin
  2931. Result := False;
  2932. Exit;
  2933. end;
  2934. end;
  2935. Result := True;
  2936. end;
  2937. function StartsWithACE(const ABytes: TIdBytes): Boolean;
  2938. const
  2939. cDash = Ord('-');
  2940. var
  2941. LS: string;
  2942. begin
  2943. Result := False;
  2944. if Length(ABytes) > 4 then
  2945. begin
  2946. if (ABytes[2] = cDash) and (ABytes[3] = cDash) then
  2947. begin
  2948. SetLength(LS, 2);
  2949. LS[1] := Char(ABytes[2]);
  2950. LS[2] := Char(ABytes[3]);
  2951. if PosInStrArray(LS, ['bl','bq','dq','lq','mq','ra','wq','zq'], False) > -1 then begin {do not localize}
  2952. Result := True;
  2953. end;
  2954. end;
  2955. end;
  2956. end;
  2957. function PosInSmallIntArray(const ASearchInt: SmallInt; const AArray: array of SmallInt): Integer;
  2958. begin
  2959. for Result := Low(AArray) to High(AArray) do begin
  2960. if ASearchInt = AArray[Result] then begin
  2961. Exit;
  2962. end;
  2963. end;
  2964. Result := -1;
  2965. end;
  2966. {This searches an array of string for an occurance of SearchStr}
  2967. function PosInStrArray(const SearchStr: string; const Contents: array of string; const CaseSensitive: Boolean = True): Integer;
  2968. begin
  2969. for Result := Low(Contents) to High(Contents) do begin
  2970. if CaseSensitive then begin
  2971. if SearchStr = Contents[Result] then begin
  2972. Exit;
  2973. end;
  2974. end else begin
  2975. if TextIsSame(SearchStr, Contents[Result]) then begin
  2976. Exit;
  2977. end;
  2978. end;
  2979. end;
  2980. Result := -1;
  2981. end;
  2982. //IPv4 address conversion
  2983. function ByteToHex(const AByte: Byte): string;
  2984. {$IFDEF USE_INLINE}inline;{$ENDIF}
  2985. begin
  2986. SetLength(Result, 2);
  2987. Result[1] := IdHexDigits[(AByte and $F0) shr 4];
  2988. Result[2] := IdHexDigits[AByte and $F];
  2989. end;
  2990. function LongWordToHex(const ALongWord : LongWord) : String;
  2991. {$IFDEF USE_INLINE}inline;{$ENDIF}
  2992. begin
  2993. Result := ByteToHex((ALongWord and $FF000000) shr 24)
  2994. + ByteToHex((ALongWord and $00FF0000) shr 16)
  2995. + ByteToHex((ALongWord and $0000FF00) shr 8)
  2996. + ByteToHex(ALongWord and $000000FF);
  2997. end;
  2998. function ToHex(const AValue: TIdBytes; const ACount: Integer = -1;
  2999. const AIndex: Integer = 0): string;
  3000. {$IFDEF USE_INLINE}inline;{$ENDIF}
  3001. var
  3002. I, LCount: Integer;
  3003. begin
  3004. LCount := IndyLength(AValue, ACount, AIndex);
  3005. if LCount > 0 then begin
  3006. SetLength(Result, LCount*2);
  3007. for I := 0 to LCount-1 do begin
  3008. Result[I*2+1] := IdHexDigits[(AValue[AIndex+I] and $F0) shr 4];
  3009. Result[I*2+2] := IdHexDigits[AValue[AIndex+I] and $F];
  3010. end;
  3011. end else begin
  3012. Result := '';
  3013. end;
  3014. end;
  3015. function ToHex(const AValue: array of LongWord): string;
  3016. var
  3017. {$IFNDEF DOTNET}
  3018. P: PByteArray;
  3019. {$ENDIF}
  3020. i: Integer;
  3021. begin
  3022. Result := '';
  3023. if Length(AValue) > 0 then
  3024. begin
  3025. {$IFNDEF DOTNET}
  3026. P := PByteArray(@AValue[0]);
  3027. SetString(Result, nil, Length(AValue)*4*2);//40
  3028. for i := 0 to Length(AValue)*4-1 do begin
  3029. Result[i*2+1] := IdHexDigits[(P^[i] and $F0) shr 4];
  3030. Result[i*2+2] := IdHexDigits[P^[i] and $F];
  3031. end;//for
  3032. {$ELSE}
  3033. for i := 0 to Length(AValue)-1 do begin
  3034. Result := Result + ToHex(ToBytes(AValue[i]));
  3035. end;
  3036. {$ENDIF}
  3037. end;
  3038. end;
  3039. function IPv4ToHex(const AIPAddress: string; const ADotted: Boolean): string;
  3040. var
  3041. i: Integer;
  3042. LBuf, LTmp: string;
  3043. begin
  3044. LBuf := Trim(AIPAddress);
  3045. Result := IdHexPrefix;
  3046. for i := 0 to 3 do begin
  3047. LTmp := ByteToHex(IndyStrToInt(Fetch(LBuf, '.', True)));
  3048. if ADotted then begin
  3049. Result := Result + '.' + IdHexPrefix + LTmp;
  3050. end else begin
  3051. Result := Result + LTmp;
  3052. end;
  3053. end;
  3054. end;
  3055. {$IFNDEF DOTNET}
  3056. function OctalToInt64(const AValue: string): Int64;
  3057. var
  3058. i: Integer;
  3059. begin
  3060. Result := 0;
  3061. for i := 1 to Length(AValue) do begin
  3062. Result := (Result shl 3) + IndyStrToInt(AValue[i], 0);
  3063. end;
  3064. end;
  3065. {$ENDIF}
  3066. function ByteToOctal(const AByte: Byte): string;
  3067. {$IFDEF USE_INLINE}inline;{$ENDIF}
  3068. begin
  3069. SetLength(Result, 3);
  3070. Result[1] := IdOctalDigits[(AByte shr 6) and $7];
  3071. Result[2] := IdOctalDigits[(AByte shr 3) and $7];
  3072. Result[3] := IdOctalDigits[AByte and $7];
  3073. if Result[1] <> '0' then begin
  3074. Result := '0' + Result;
  3075. end;
  3076. end;
  3077. function IPv4ToOctal(const AIPAddress: string): string;
  3078. var
  3079. i: Integer;
  3080. LBuf: string;
  3081. begin
  3082. LBuf := Trim(AIPAddress);
  3083. Result := ByteToOctal(IndyStrToInt(Fetch(LBuf, '.', True), 0));
  3084. for i := 0 to 2 do begin
  3085. Result := Result + '.' + ByteToOctal(IndyStrToInt(Fetch(LBuf, '.', True), 0));
  3086. end;
  3087. end;
  3088. procedure CopyTIdBytes(const ASource: TIdBytes; const ASourceIndex: Integer;
  3089. var VDest: TIdBytes; const ADestIndex: Integer; const ALength: Integer);
  3090. {$IFDEF USE_INLINE}inline;{$ENDIF}
  3091. begin
  3092. {$IFDEF DOTNET}
  3093. System.array.Copy(ASource, ASourceIndex, VDest, ADestIndex, ALength);
  3094. {$ELSE}
  3095. //if these asserts fail, then it indicates an attempted buffer overrun.
  3096. Assert(ASourceIndex >= 0);
  3097. Assert((ASourceIndex+ALength) <= Length(ASource));
  3098. Move(ASource[ASourceIndex], VDest[ADestIndex], ALength);
  3099. {$ENDIF}
  3100. end;
  3101. procedure CopyTIdChar(const ASource: Char; var VDest: TIdBytes; const ADestIndex: Integer;
  3102. ADestEncoding: TIdTextEncoding = nil
  3103. {$IFDEF STRING_IS_ANSI}; ASrcEncoding: TIdTextEncoding = nil{$ENDIF}
  3104. );
  3105. var
  3106. LChars: {$IFDEF DOTNET}array[0..0] of Char{$ELSE}TIdWideChars{$ENDIF};
  3107. begin
  3108. EnsureEncoding(ADestEncoding);
  3109. {$IFDEF STRING_IS_UNICODE}
  3110. {$IFNDEF DOTNET}
  3111. SetLength(LChars, 1);
  3112. {$ENDIF}
  3113. LChars[0] := ASource;
  3114. ADestEncoding.GetBytes(LChars, 0, 1, VDest, ADestIndex);
  3115. {$ELSE}
  3116. EnsureEncoding(ASrcEncoding, encOSDefault);
  3117. LChars := ASrcEncoding.GetChars(RawToBytes(ASource, 1));
  3118. ADestEncoding.GetBytes(LChars, 0, Length(LChars), VDest, ADestIndex);
  3119. {$ENDIF}
  3120. end;
  3121. procedure CopyTIdShort(const ASource: Short; var VDest: TIdBytes; const ADestIndex: Integer);
  3122. {$IFDEF DOTNET}
  3123. var
  3124. LShort : TIdBytes;
  3125. {$ELSE}
  3126. {$IFDEF USE_INLINE}inline;{$ENDIF}
  3127. {$ENDIF}
  3128. begin
  3129. {$IFDEF DOTNET}
  3130. LShort := System.BitConverter.GetBytes(ASource);
  3131. System.array.Copy(LShort, 0, VDest, ADestIndex, SizeOf(Short));
  3132. {$ELSE}
  3133. PSmallInt(@VDest[ADestIndex])^ := ASource;
  3134. {$ENDIF}
  3135. end;
  3136. procedure CopyTIdWord(const ASource: Word; var VDest: TIdBytes; const ADestIndex: Integer);
  3137. {$IFDEF DOTNET}
  3138. var
  3139. LWord : TIdBytes;
  3140. {$ELSE}
  3141. {$IFDEF USE_INLINE}inline;{$ENDIF}
  3142. {$ENDIF}
  3143. begin
  3144. {$IFDEF DOTNET}
  3145. LWord := System.BitConverter.GetBytes(ASource);
  3146. System.array.Copy(LWord, 0, VDest, ADestIndex, SizeOf(Word));
  3147. {$ELSE}
  3148. PWord(@VDest[ADestIndex])^ := ASource;
  3149. {$ENDIF}
  3150. end;
  3151. procedure CopyTIdLongWord(const ASource: LongWord; var VDest: TIdBytes; const ADestIndex: Integer);
  3152. {$IFDEF DOTNET}
  3153. var
  3154. LWord : TIdBytes;
  3155. {$ELSE}
  3156. {$IFDEF USE_INLINE}inline;{$ENDIF}
  3157. {$ENDIF}
  3158. begin
  3159. {$IFDEF DOTNET}
  3160. LWord := System.BitConverter.GetBytes(ASource);
  3161. System.array.Copy(LWord, 0, VDest, ADestIndex, SizeOf(LongWord));
  3162. {$ELSE}
  3163. PLongWord(@VDest[ADestIndex])^ := ASource;
  3164. {$ENDIF}
  3165. end;
  3166. procedure CopyTIdLongInt(const ASource: LongInt; var VDest: TIdBytes; const ADestIndex: Integer);
  3167. {$IFDEF DOTNET}
  3168. var
  3169. LInt : TIdBytes;
  3170. {$ELSE}
  3171. {$IFDEF USE_INLINE}inline;{$ENDIF}
  3172. {$ENDIF}
  3173. begin
  3174. {$IFDEF DOTNET}
  3175. LInt := System.BitConverter.GetBytes(ASource);
  3176. System.array.Copy(LInt, 0, VDest, ADestIndex, SizeOf(LongInt));
  3177. {$ELSE}
  3178. PLongInt(@VDest[ADestIndex])^ := ASource;
  3179. {$ENDIF}
  3180. end;
  3181. procedure CopyTIdInt64(const ASource: Int64; var VDest: TIdBytes; const ADestIndex: Integer);
  3182. {$IFDEF DOTNET}
  3183. var
  3184. LWord : TIdBytes;
  3185. {$ELSE}
  3186. {$IFDEF USE_INLINE}inline;{$ENDIF}
  3187. {$ENDIF}
  3188. begin
  3189. {$IFDEF DOTNET}
  3190. LWord := System.BitConverter.GetBytes(ASource);
  3191. System.array.Copy(LWord, 0, VDest, ADestIndex, SizeOf(Int64));
  3192. {$ELSE}
  3193. PInt64(@VDest[ADestIndex])^ := ASource;
  3194. {$ENDIF}
  3195. end;
  3196. procedure CopyTIdIPV6Address(const ASource: TIdIPv6Address; var VDest: TIdBytes; const ADestIndex: Integer);
  3197. {$IFDEF DOTNET}
  3198. var
  3199. i : Integer;
  3200. {$ELSE}
  3201. {$IFDEF USE_INLINE}inline;{$ENDIF}
  3202. {$ENDIF}
  3203. begin
  3204. {$IFDEF DOTNET}
  3205. for i := 0 to 7 do begin
  3206. CopyTIdWord(ASource[i], VDest, ADestIndex + (i * 2));
  3207. end;
  3208. {$ELSE}
  3209. Move(ASource, VDest[ADestIndex], 16);
  3210. {$ENDIF}
  3211. end;
  3212. procedure CopyTIdByteArray(const ASource: array of Byte; const ASourceIndex: Integer;
  3213. var VDest: TIdBytes; const ADestIndex: Integer; const ALength: Integer);
  3214. begin
  3215. {$IFDEF DOTNET}
  3216. System.array.Copy(ASource, ASourceIndex, VDest, ADestIndex, ALength);
  3217. {$ELSE}
  3218. Move(ASource[ASourceIndex], VDest[ADestIndex], ALength);
  3219. {$ENDIF}
  3220. end;
  3221. procedure CopyTIdString(const ASource: String; var VDest: TIdBytes;
  3222. const ADestIndex: Integer; const ALength: Integer = -1;
  3223. ADestEncoding: TIdTextEncoding = nil
  3224. {$IFDEF STRING_IS_ANSI}; ASrcEncoding: TIdTextEncoding = nil{$ENDIF}
  3225. ); overload;
  3226. {$IFDEF USE_INLINE}inline;{$ENDIF}
  3227. begin
  3228. CopyTIdString(ASource, 1, VDest, ADestIndex, ALength, ADestEncoding
  3229. {$IFDEF STRING_IS_ANSI}, ASrcEncoding{$ENDIF}
  3230. );
  3231. end;
  3232. procedure CopyTIdString(const ASource: String; const ASourceIndex: Integer;
  3233. var VDest: TIdBytes; const ADestIndex: Integer; const ALength: Integer = -1;
  3234. ADestEncoding: TIdTextEncoding = nil
  3235. {$IFDEF STRING_IS_ANSI}; ASrcEncoding: TIdTextEncoding = nil{$ENDIF}
  3236. ); overload;
  3237. {$IFDEF USE_INLINE}inline;{$ENDIF}
  3238. var
  3239. LLength: Integer;
  3240. {$IFDEF STRING_IS_ANSI}
  3241. LTmp: TIdWideChars;
  3242. {$ENDIF}
  3243. begin
  3244. {$IFDEF STRING_IS_ANSI}
  3245. LTmp := nil; // keep the compiler happy
  3246. {$ENDIF}
  3247. LLength := IndyLength(ASource, ALength, ASourceIndex);
  3248. if LLength > 0 then begin
  3249. EnsureEncoding(ADestEncoding);
  3250. {$IFDEF STRING_IS_UNICODE}
  3251. ADestEncoding.GetBytes(ASource, ASourceIndex{$IFDEF DOTNET}-1{$ENDIF}, LLength, VDest, ADestIndex);
  3252. {$ELSE}
  3253. EnsureEncoding(ASrcEncoding, encOSDefault);
  3254. LTmp := ASrcEncoding.GetChars(RawToBytes(ASource[ASourceIndex], LLength)); // convert to Unicode
  3255. ADestEncoding.GetBytes(LTmp, 0, Length(LTmp), VDest, ADestIndex);
  3256. {$ENDIF}
  3257. end;
  3258. end;
  3259. procedure DebugOutput(const AText: string);
  3260. {$IFDEF WINDOWS}
  3261. {$IFDEF UNICODE_BUT_STRING_IS_ANSI}
  3262. var
  3263. LTemp: WideString;
  3264. {$ELSE}
  3265. {$IFDEF USE_INLINE}inline;{$ENDIF}
  3266. {$ENDIF}
  3267. {$ELSE}
  3268. {$IFDEF USE_INLINE}inline;{$ENDIF}
  3269. {$ENDIF}
  3270. begin
  3271. {$IFDEF KYLIX}
  3272. __write(stderr, AText, Length(AText));
  3273. __write(stderr, EOL, Length(EOL));
  3274. {$ENDIF}
  3275. {$IFDEF WINDOWS}
  3276. {$IFDEF UNICODE_BUT_STRING_IS_ANSI}
  3277. LTemp := WideString(AText); // explicit convert to Unicode
  3278. OutputDebugString(PWideChar(LTemp));
  3279. {$ELSE}
  3280. OutputDebugString(PChar(AText));
  3281. {$ENDIF}
  3282. {$ENDIF}
  3283. {$IFDEF DOTNET}
  3284. System.Diagnostics.Debug.WriteLine(AText);
  3285. {$ENDIF}
  3286. end;
  3287. function CurrentThreadId: TIdThreadID;
  3288. {$IFDEF USE_INLINE}inline;{$ENDIF}
  3289. begin
  3290. {$IFDEF DOTNET}
  3291. {$IFDEF DOTNET_2_OR_ABOVE}
  3292. {
  3293. [Warning] IdGlobal.pas(1416): W1000 Symbol 'GetCurrentThreadId'
  3294. is deprecated: 'AppDomain.GetCurrentThreadId has been deprecated because
  3295. it does not provide a stable Id when managed threads are running on fibers
  3296. (aka lightweight threads). To get a stable identifier for a managed thread,
  3297. use the ManagedThreadId property on Thread.
  3298. http://go.microsoft.com/fwlink/?linkid=14202'
  3299. }
  3300. Result := System.Threading.Thread.CurrentThread.ManagedThreadId;
  3301. // Thread.ManagedThreadId;
  3302. {$ENDIF}
  3303. {$IFDEF DOTNET_1_1}
  3304. // 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)
  3305. Result := AppDomain.GetCurrentThreadId;
  3306. // RLebeau
  3307. // TODO: find if there is something like the following instead:
  3308. // System.Diagnostics.Thread.GetCurrentThread.ID
  3309. // System.Threading.Thread.CurrentThread.ID
  3310. {$ENDIF}
  3311. {$ELSE}
  3312. // TODO: is GetCurrentThreadId() available on Linux?
  3313. Result := GetCurrentThreadID;
  3314. {$ENDIF}
  3315. end;
  3316. function CurrentProcessId: TIdPID;
  3317. {$IFDEF USE_INLINE}inline;{$ENDIF}
  3318. begin
  3319. {$IFDEF KYLIXCOMPAT}
  3320. Result := getpid;
  3321. {$ENDIF}
  3322. {$IFDEF USE_VCL_POSIX}
  3323. Result := getpid;
  3324. {$ENDIF}
  3325. {$IFDEF USE_BASEUNIX}
  3326. Result := fpgetpid;
  3327. {$ENDIF}
  3328. {$IFDEF WINDOWS}
  3329. Result := GetCurrentProcessID;
  3330. {$ENDIF}
  3331. {$IFDEF DOTNET}
  3332. Result := System.Diagnostics.Process.GetCurrentProcess.ID;
  3333. {$ENDIF}
  3334. end;
  3335. function Fetch(var AInput: string; const ADelim: string = IdFetchDelimDefault;
  3336. const ADelete: Boolean = IdFetchDeleteDefault;
  3337. const ACaseSensitive: Boolean = IdFetchCaseSensitiveDefault): string;
  3338. {$IFDEF USE_INLINE}inline;{$ENDIF}
  3339. var
  3340. LPos: Integer;
  3341. begin
  3342. if ACaseSensitive then begin
  3343. if ADelim = #0 then begin
  3344. // AnsiPos does not work with #0
  3345. LPos := Pos(ADelim, AInput);
  3346. end else begin
  3347. LPos := IndyPos(ADelim, AInput);
  3348. end;
  3349. if LPos = 0 then begin
  3350. Result := AInput;
  3351. if ADelete then begin
  3352. AInput := ''; {Do not Localize}
  3353. end;
  3354. end
  3355. else begin
  3356. Result := Copy(AInput, 1, LPos - 1);
  3357. if ADelete then begin
  3358. //slower Delete(AInput, 1, LPos + Length(ADelim) - 1); because the
  3359. //remaining part is larger than the deleted
  3360. AInput := Copy(AInput, LPos + Length(ADelim), MaxInt);
  3361. end;
  3362. end;
  3363. end else begin
  3364. Result := FetchCaseInsensitive(AInput, ADelim, ADelete);
  3365. end;
  3366. end;
  3367. function FetchCaseInsensitive(var AInput: string; const ADelim: string;
  3368. const ADelete: Boolean): string;
  3369. {$IFDEF USE_INLINE}inline;{$ENDIF}
  3370. var
  3371. LPos: Integer;
  3372. begin
  3373. if ADelim = #0 then begin
  3374. // AnsiPos does not work with #0
  3375. LPos := Pos(ADelim, AInput);
  3376. end else begin
  3377. //? may be AnsiUpperCase?
  3378. LPos := IndyPos(UpperCase(ADelim), UpperCase(AInput));
  3379. end;
  3380. if LPos = 0 then begin
  3381. Result := AInput;
  3382. if ADelete then begin
  3383. AInput := ''; {Do not Localize}
  3384. end;
  3385. end else begin
  3386. Result := Copy(AInput, 1, LPos - 1);
  3387. if ADelete then begin
  3388. //faster than Delete(AInput, 1, LPos + Length(ADelim) - 1); because the
  3389. //remaining part is larger than the deleted
  3390. AInput := Copy(AInput, LPos + Length(ADelim), MaxInt);
  3391. end;
  3392. end;
  3393. end;
  3394. function GetThreadHandle(AThread: TThread): TIdThreadHandle;
  3395. {$IFDEF USE_INLINE}inline;{$ENDIF}
  3396. begin
  3397. {$IFDEF UNIX}
  3398. Result := AThread.ThreadID; // RLebeau: is it right to return an ID where a thread object handle is expected instead?
  3399. {$ENDIF}
  3400. {$IFDEF WINDOWS}
  3401. Result := AThread.Handle;
  3402. {$ENDIF}
  3403. {$IFDEF DOTNET}
  3404. Result := AThread.Handle;
  3405. {$ENDIF}
  3406. end;
  3407. function Ticks: LongWord;
  3408. {$IFDEF DOTNET}
  3409. {$IFDEF USE_INLINE}inline;{$ENDIF}
  3410. {$ENDIF}
  3411. {$IFDEF UNIX}
  3412. {$IFDEF MACOSX}
  3413. {$IFDEF USE_INLINE} inline;{$ENDIF}
  3414. {$ELSE}
  3415. var
  3416. tv: timeval;
  3417. {$ENDIF}
  3418. {$ENDIF}
  3419. {$IFDEF WINDOWS}
  3420. {$IFDEF USE_HI_PERF_COUNTER_FOR_TICKS}
  3421. var
  3422. nTime, freq: {$IFDEF WINCE}LARGE_INTEGER{$ELSE}Int64{$ENDIF};
  3423. {$ENDIF}
  3424. {$ENDIF}
  3425. begin
  3426. {$IFDEF UNIX}
  3427. {$IFDEF MACOSX}
  3428. //This seems to be available on the Delphi cross-compiler for OS/X
  3429. Result := AbsoluteToNanoseconds(UpTime) div 1000000;
  3430. {$ELSE}
  3431. {$IFDEF USE_BASEUNIX}
  3432. fpgettimeofday(@tv,nil);
  3433. {$ENDIF}
  3434. {$IFDEF KYLIXCOMPAT}
  3435. gettimeofday(tv, nil);
  3436. {$ENDIF}
  3437. {$RANGECHECKS OFF}
  3438. Result := Int64(tv.tv_sec) * 1000 + tv.tv_usec div 1000;
  3439. {
  3440. I've implemented this correctly for now. I'll argue for using
  3441. an int64 internally, since apparently quite some functionality
  3442. (throttle, etc etc) depends on it, and this value may wrap
  3443. at any point in time.
  3444. For Windows: Uptime > 72 hours isn't really that rare any more,
  3445. For Linux: no control over when this wraps.
  3446. IdEcho has code to circumvent the wrap, but its not very good
  3447. to have code for that at all spots where it might be relevant.
  3448. }
  3449. {$ENDIF}
  3450. {$ENDIF}
  3451. {$IFDEF WINDOWS}
  3452. // S.G. 27/11/2002: Changed to use high-performance counters as per suggested
  3453. // S.G. 27/11/2002: by David B. Ferguson (david.mcs@ns.sympatico.ca)
  3454. // RLebeau 11/12/2009: removed the high-performance counters again. They
  3455. // are not reliable on multi-core systems, and are now starting to cause
  3456. // problems with TIdIOHandler.ReadLn() timeouts under Windows XP SP3, both
  3457. // 32-bit and 64-bit. Refer to these discussions:
  3458. //
  3459. // http://www.virtualdub.org/blog/pivot/entry.php?id=106
  3460. // http://blogs.msdn.com/oldnewthing/archive/2008/09/08/8931563.aspx
  3461. {$IFDEF USE_HI_PERF_COUNTER_FOR_TICKS}
  3462. {$IFDEF WINCE}
  3463. if Windows.QueryPerformanceCounter(@nTime) then begin
  3464. if Windows.QueryPerformanceFrequency(@freq) then begin
  3465. Result := Trunc((nTime.QuadPart / Freq.QuadPart) * 1000) and High(LongWord);
  3466. Exit;
  3467. end;
  3468. end;
  3469. {$ELSE}
  3470. if Windows.QueryPerformanceCounter(nTime) then begin
  3471. if Windows.QueryPerformanceFrequency(freq) then begin
  3472. Result := Trunc((nTime / Freq) * 1000) and High(LongWord);
  3473. Exit;
  3474. end;
  3475. end;
  3476. {$ENDIF}
  3477. {$ENDIF}
  3478. Result := Windows.GetTickCount;
  3479. {$ENDIF}
  3480. {$IFDEF DOTNET}
  3481. // Must cast to a cardinal
  3482. //
  3483. // http://lists.ximian.com/archives/public/mono-bugs/2003-November/009293.html
  3484. // Other references in Google.
  3485. // Bug in .NET. It acts like Win32, not as per .NET docs but goes negative after 25 days.
  3486. //
  3487. // There may be a problem in the future if .NET changes this to work as docced with 25 days.
  3488. // Will need to check our routines then and somehow counteract / detect this.
  3489. // One possibility is that we could just wrap it ourselves in this routine.
  3490. Result := LongWord(Environment.TickCount);
  3491. {$ENDIF}
  3492. end;
  3493. function GetTickDiff(const AOldTickCount, ANewTickCount: LongWord): LongWord;
  3494. {$IFDEF USE_INLINE}inline;{$ENDIF}
  3495. begin
  3496. {This is just in case the TickCount rolled back to zero}
  3497. if ANewTickCount >= AOldTickCount then begin
  3498. Result := ANewTickCount - AOldTickCount;
  3499. end else begin
  3500. Result := High(LongWord) - AOldTickCount + ANewTickCount;
  3501. end;
  3502. end;
  3503. {$IFNDEF DOTNET}
  3504. function ServicesFilePath: string;
  3505. var
  3506. {$IFDEF MSWINDOWS}
  3507. sLocation: {$IFDEF UNICODE_BUT_STRING_IS_ANSI}WideString{$ELSE}string{$ENDIF};
  3508. {$ELSE}
  3509. sLocation: string;
  3510. {$ENDIF}
  3511. begin
  3512. {$IFDEF UNIX}
  3513. sLocation := '/etc/'; // assume Berkeley standard placement {do not localize}
  3514. {$ENDIF}
  3515. {$IFDEF MSWINDOWS}
  3516. SetLength(sLocation, MAX_PATH);
  3517. SetLength(sLocation, GetWindowsDirectory(PChar(sLocation), MAX_PATH));
  3518. sLocation := IndyIncludeTrailingPathDelimiter(sLocation);
  3519. if Win32Platform = VER_PLATFORM_WIN32_NT then begin
  3520. sLocation := sLocation + 'system32\drivers\etc\'; {do not localize}
  3521. end;
  3522. {$ENDIF}
  3523. Result := sLocation + 'services'; {do not localize}
  3524. end;
  3525. {$ENDIF}
  3526. {$IFNDEF DOTNET}
  3527. // IdPorts returns a list of defined ports in /etc/services
  3528. function IdPorts: TList;
  3529. var
  3530. s: string;
  3531. idx, iPosSlash: {$IFDEF BYTE_COMPARE_SETS}Byte{$ELSE}Integer{$ENDIF};
  3532. i, iPrev: PtrInt;
  3533. sl: TStringList;
  3534. begin
  3535. if GIdPorts = nil then
  3536. begin
  3537. GIdPorts := TList.Create;
  3538. sl := TStringList.Create;
  3539. try
  3540. sl.LoadFromFile(ServicesFilePath); {do not localize}
  3541. iPrev := 0;
  3542. for idx := 0 to sl.Count - 1 do
  3543. begin
  3544. s := sl[idx];
  3545. iPosSlash := IndyPos('/', s); {do not localize}
  3546. if (iPosSlash > 0) and (not (IndyPos('#', s) in [1..iPosSlash])) then {do not localize}
  3547. begin // presumably found a port number that isn't commented {Do not Localize}
  3548. i := iPosSlash;
  3549. repeat
  3550. Dec(i);
  3551. if i = 0 then begin
  3552. raise EIdCorruptServicesFile.CreateFmt(RSCorruptServicesFile, [ServicesFilePath]); {do not localize}
  3553. end;
  3554. //TODO: Make Whitespace a function to elim warning
  3555. until Ord(s[i]) in IdWhiteSpace;
  3556. i := IndyStrToInt(Copy(s, i+1, iPosSlash-i-1));
  3557. if i <> iPrev then begin
  3558. GIdPorts.Add(Pointer(i));
  3559. end;
  3560. iPrev := i;
  3561. end;
  3562. end;
  3563. finally
  3564. sl.Free;
  3565. end;
  3566. end;
  3567. Result := GIdPorts;
  3568. end;
  3569. {$ENDIF}
  3570. function iif(ATest: Boolean; const ATrue: Integer; const AFalse: Integer): Integer;
  3571. {$IFDEF USE_INLINE}inline;{$ENDIF}
  3572. begin
  3573. if ATest then begin
  3574. Result := ATrue;
  3575. end else begin
  3576. Result := AFalse;
  3577. end;
  3578. end;
  3579. function iif(ATest: Boolean; const ATrue: string; const AFalse: string): string;
  3580. {$IFDEF USE_INLINE}inline;{$ENDIF}
  3581. begin
  3582. if ATest then begin
  3583. Result := ATrue;
  3584. end else begin
  3585. Result := AFalse;
  3586. end;
  3587. end;
  3588. function iif(ATest: Boolean; const ATrue: Boolean; const AFalse: Boolean): Boolean;
  3589. {$IFDEF USE_INLINE}inline;{$ENDIF}
  3590. begin
  3591. if ATest then begin
  3592. Result := ATrue;
  3593. end else begin
  3594. Result := AFalse;
  3595. end;
  3596. end;
  3597. function iif(const AEncoding, ADefEncoding: TIdTextEncoding; ADefEncodingType: IdAnsiEncodingType = encASCII): TIdTextEncoding;
  3598. {$IFDEF USE_INLINE}inline;{$ENDIF}
  3599. begin
  3600. Result := AEncoding;
  3601. if Result = nil then
  3602. begin
  3603. Result := ADefEncoding;
  3604. EnsureEncoding(Result, ADefEncodingType);
  3605. end;
  3606. end;
  3607. function InMainThread: Boolean;
  3608. {$IFDEF USE_INLINE}inline;{$ENDIF}
  3609. begin
  3610. {$IFDEF DOTNET}
  3611. Result := System.Threading.Thread.CurrentThread = MainThread;
  3612. {$ELSE}
  3613. Result := GetCurrentThreadID = MainThreadID;
  3614. {$ENDIF}
  3615. end;
  3616. procedure WriteMemoryStreamToStream(Src: TMemoryStream; Dest: TStream; Count: TIdStreamSize);
  3617. {$IFDEF USE_INLINE}inline;{$ENDIF}
  3618. begin
  3619. {$IFDEF DOTNET}
  3620. Dest.Write(Src.Memory, Count);
  3621. {$ELSE}
  3622. Dest.Write(Src.Memory^, Count);
  3623. {$ENDIF}
  3624. end;
  3625. {$IFNDEF DOTNET_EXCLUDE}
  3626. function IsCurrentThread(AThread: TThread): Boolean;
  3627. {$IFDEF USE_INLINE}inline;{$ENDIF}
  3628. begin
  3629. Result := AThread.ThreadID = GetCurrentThreadID;
  3630. end;
  3631. {$ENDIF}
  3632. //convert a dword into an IPv4 address in dotted form
  3633. function MakeDWordIntoIPv4Address(const ADWord: LongWord): string;
  3634. {$IFDEF USE_INLINE}inline;{$ENDIF}
  3635. begin
  3636. Result := IntToStr((ADWord shr 24) and $FF) + '.';
  3637. Result := Result + IntToStr((ADWord shr 16) and $FF) + '.';
  3638. Result := Result + IntToStr((ADWord shr 8) and $FF) + '.';
  3639. Result := Result + IntToStr(ADWord and $FF);
  3640. end;
  3641. function IsAlpha(const AChar: Char): Boolean;
  3642. {$IFDEF USE_INLINE}inline;{$ENDIF}
  3643. begin
  3644. // TODO: under D2009+, use TCharacter.IsLetter() instead
  3645. // Do not use IsCharAlpha or IsCharAlphaNumeric - they are Win32 routines
  3646. Result := ((AChar >= 'a') and (AChar <= 'z')) or ((AChar >= 'A') and (AChar <= 'Z')); {Do not Localize}
  3647. end;
  3648. function IsAlpha(const AString: String; const ALength: Integer = -1; const AIndex: Integer = 1): Boolean;
  3649. {$IFDEF USE_INLINE}inline;{$ENDIF}
  3650. var
  3651. i: Integer;
  3652. LLen: Integer;
  3653. begin
  3654. Result := False;
  3655. LLen := IndyLength(AString, ALength, AIndex);
  3656. if LLen > 0 then begin
  3657. for i := 0 to LLen-1 do begin
  3658. if not IsAlpha(AString[AIndex+i]) then begin
  3659. Exit;
  3660. end;
  3661. end;
  3662. Result := True;
  3663. end;
  3664. end;
  3665. function IsAlphaNumeric(const AChar: Char): Boolean;
  3666. {$IFDEF USE_INLINE}inline;{$ENDIF}
  3667. begin
  3668. // Do not use IsCharAlpha or IsCharAlphaNumeric - they are Win32 routines
  3669. Result := IsAlpha(AChar) or IsNumeric(AChar);
  3670. end;
  3671. function IsAlphaNumeric(const AString: String; const ALength: Integer = -1; const AIndex: Integer = 1): Boolean;
  3672. {$IFDEF USE_INLINE}inline;{$ENDIF}
  3673. var
  3674. i: Integer;
  3675. LLen: Integer;
  3676. begin
  3677. Result := False;
  3678. LLen := IndyLength(AString, ALength, AIndex);
  3679. if LLen > 0 then begin
  3680. for i := 0 to LLen-1 do begin
  3681. if not IsAlphaNumeric(AString[AIndex+i]) then begin
  3682. Exit;
  3683. end;
  3684. end;
  3685. Result := True;
  3686. end;
  3687. end;
  3688. function IsOctal(const AChar: Char): Boolean; overload;
  3689. {$IFDEF USE_INLINE}inline;{$ENDIF}
  3690. begin
  3691. Result := (AChar >= '0') and (AChar <= '7') {Do not Localize}
  3692. end;
  3693. function IsOctal(const AString: string; const ALength: Integer = -1; const AIndex: Integer = 1): Boolean; overload;
  3694. {$IFDEF USE_INLINE}inline;{$ENDIF}
  3695. var
  3696. i: Integer;
  3697. LLen: Integer;
  3698. begin
  3699. Result := False;
  3700. LLen := IndyLength(AString, ALength, AIndex);
  3701. if LLen > 0 then begin
  3702. for i := 0 to LLen-1 do begin
  3703. if not IsOctal(AString[AIndex+i]) then begin
  3704. Exit;
  3705. end;
  3706. end;
  3707. Result := True;
  3708. end;
  3709. end;
  3710. function IsHexidecimal(const AChar: Char): Boolean; overload;
  3711. {$IFDEF USE_INLINE}inline;{$ENDIF}
  3712. begin
  3713. Result := IsNumeric(AChar)
  3714. or ((AChar >= 'A') and (AChar <= 'F')) {Do not Localize}
  3715. or ((AChar >= 'a') and (AChar <= 'f')); {Do not Localize}
  3716. end;
  3717. function IsHexidecimal(const AString: string; const ALength: Integer = -1; const AIndex: Integer = 1): Boolean; overload;
  3718. {$IFDEF USE_INLINE}inline;{$ENDIF}
  3719. var
  3720. i: Integer;
  3721. LLen: Integer;
  3722. begin
  3723. Result := False;
  3724. LLen := IndyLength(AString, ALength, AIndex);
  3725. if LLen > 0 then begin
  3726. for i := 0 to LLen-1 do begin
  3727. if not IsHexidecimal(AString[AIndex+i]) then begin
  3728. Exit;
  3729. end;
  3730. end;
  3731. Result := True;
  3732. end;
  3733. end;
  3734. {$HINTS OFF}
  3735. function IsNumeric(const AString: string): Boolean;
  3736. var
  3737. LCode: Integer;
  3738. LVoid: Int64;
  3739. begin
  3740. Val(AString, LVoid, LCode);
  3741. Result := LCode = 0;
  3742. end;
  3743. {$HINTS ON}
  3744. function IsNumeric(const AString: string; const ALength: Integer; const AIndex: Integer = 1): Boolean;
  3745. var
  3746. I: Integer;
  3747. LLen: Integer;
  3748. begin
  3749. Result := False;
  3750. LLen := IndyLength(AString, ALength, AIndex);
  3751. if LLen > 0 then begin
  3752. for I := 0 to LLen-1 do begin
  3753. if not IsNumeric(AString[AIndex+i]) then begin
  3754. Exit;
  3755. end;
  3756. end;
  3757. Result := True;
  3758. end;
  3759. end;
  3760. function IsNumeric(const AChar: Char): Boolean;
  3761. {$IFDEF USE_INLINE}inline;{$ENDIF}
  3762. begin
  3763. // TODO: under D2009+, use TCharacter.IsDigit() instead
  3764. // Do not use IsCharAlpha or IsCharAlphaNumeric - they are Win32 routines
  3765. Result := (AChar >= '0') and (AChar <= '9'); {Do not Localize}
  3766. end;
  3767. {
  3768. This is an adaptation of the StrToInt64 routine in SysUtils.
  3769. We had to adapt it to work with Int64 because the one with Integers
  3770. can not deal with anything greater than MaxInt and IP addresses are
  3771. always $0-$FFFFFFFF (unsigned)
  3772. }
  3773. {$IFNDEF HAS_StrToInt64Def}
  3774. function StrToInt64Def(const S: string; const Default: Integer): Int64;
  3775. {$IFDEF USE_INLINE}inline;{$ENDIF}
  3776. var
  3777. E: Integer;
  3778. begin
  3779. Val(S, Result, E);
  3780. if E <> 0 then begin
  3781. Result := Default;
  3782. end;
  3783. end;
  3784. {$ENDIF}
  3785. function IPv4MakeLongWordInRange(const AInt: Int64; const A256Power: Integer): LongWord;
  3786. {$IFDEF USE_INLINE}inline;{$ENDIF}
  3787. //Note that this function is only for stripping off some extra bits
  3788. //from an address that might appear in some spam E-Mails.
  3789. begin
  3790. case A256Power of
  3791. 4: Result := (AInt and POWER_4);
  3792. 3: Result := (AInt and POWER_3);
  3793. 2: Result := (AInt and POWER_2);
  3794. else
  3795. {$IFDEF FPC}
  3796. Result := Lo(AInt and POWER_1);
  3797. {$ELSE}
  3798. Result := AInt and POWER_1;
  3799. {$ENDIF}
  3800. end;
  3801. end;
  3802. function IPv4ToDWord(const AIPAddress: string): LongWord; overload;
  3803. {$IFDEF USE_INLINE}inline;{$ENDIF}
  3804. var
  3805. LErr: Boolean;
  3806. begin
  3807. Result := IPv4ToDWord(AIPAddress, LErr);
  3808. end;
  3809. function IPv4ToDWord(const AIPAddress: string; var VErr: Boolean): LongWord; overload;
  3810. var
  3811. {$IFDEF DOTNET}
  3812. AIPaddr: IPAddress;
  3813. {$ELSE}
  3814. LBuf, LBuf2: string;
  3815. L256Power: Integer;
  3816. LParts: Integer; //how many parts should we process at a time
  3817. {$ENDIF}
  3818. begin
  3819. VErr := True;
  3820. Result := 0;
  3821. {$IFDEF DOTNET}
  3822. AIPaddr := System.Net.IPAddress.Parse(AIPAddress);
  3823. try
  3824. try
  3825. if AIPaddr.AddressFamily = Addressfamily.InterNetwork then begin
  3826. {$IFDEF DOTNET_2_OR_ABOVE}
  3827. //This looks funny but it's just to circvument a warning about
  3828. //a depreciated property in AIPaddr. We can safely assume
  3829. //this is an IPv4 address.
  3830. Result := BytesToLongWord( AIPAddr.GetAddressBytes,0);
  3831. {$ENDIF}
  3832. {$IFDEF DOTNET_1_1}
  3833. Result := AIPaddr.Address;
  3834. {$ENDIF}
  3835. VErr := False;
  3836. end;
  3837. except
  3838. VErr := True;
  3839. end;
  3840. finally
  3841. FreeAndNil(AIPaddr);
  3842. end;
  3843. {$ELSE}
  3844. // S.G. 11/8/2003: Added overflow checking disabling and change multiplys by SHLs.
  3845. // Locally disable overflow checking so we can safely use SHL and SHR
  3846. {$IFOPT Q+} // detect overflow checking
  3847. {$DEFINE _QPlusWasEnabled}
  3848. {$Q-}
  3849. {$ENDIF}
  3850. L256Power := 4;
  3851. LBuf2 := AIPAddress;
  3852. repeat
  3853. LBuf := Fetch(LBuf2, '.');
  3854. if LBuf = '' then begin
  3855. Break;
  3856. end;
  3857. //We do things this way because we have to treat
  3858. //IP address parts differently than a whole number
  3859. //and sometimes, there can be missing periods.
  3860. if (LBuf2 = '') and (L256Power > 1) then begin
  3861. LParts := L256Power;
  3862. Result := Result shl (L256Power SHL 3);
  3863. end else begin
  3864. LParts := 1;
  3865. Result := Result shl 8;
  3866. end;
  3867. if TextStartsWith(LBuf, IdHexPrefix) then begin
  3868. //this is a hexideciaml number
  3869. if not IsHexidecimal(Copy(LBuf, 3, MaxInt)) then begin
  3870. Exit;
  3871. end;
  3872. Result := Result + IPv4MakeLongWordInRange(StrToInt64Def(LBuf, 0), LParts);
  3873. end else begin
  3874. if not IsNumeric(LBuf) then begin
  3875. //There was an error meaning an invalid IP address
  3876. Exit;
  3877. end;
  3878. if TextStartsWith(LBuf, '0') and IsOctal(LBuf) then begin {do not localize}
  3879. //this is octal
  3880. Result := Result + IPv4MakeLongWordInRange(OctalToInt64(LBuf), LParts);
  3881. end else begin
  3882. //this must be a decimal
  3883. Result := Result + IPv4MakeLongWordInRange(StrToInt64Def(LBuf, 0), LParts);
  3884. end;
  3885. end;
  3886. Dec(L256Power);
  3887. until False;
  3888. VErr := False;
  3889. // Restore overflow checking
  3890. {$IFDEF _QPlusWasEnabled} // detect previous setting
  3891. {$UNDEF _QPlusWasEnabled}
  3892. {$Q+}
  3893. {$ENDIF}
  3894. {$ENDIF}
  3895. end;
  3896. function IPv6AddressToStr(const AValue: TIdIPv6Address): string;
  3897. {$IFDEF USE_INLINE}inline;{$ENDIF}
  3898. var
  3899. i: Integer;
  3900. begin
  3901. Result := '';
  3902. for i := 0 to 7 do begin
  3903. Result := Result + ':' + IntToHex(AValue[i], 4);
  3904. end;
  3905. end;
  3906. function MakeCanonicalIPv4Address(const AAddr: string): string;
  3907. {$IFDEF USE_INLINE}inline;{$ENDIF}
  3908. var
  3909. LErr: Boolean;
  3910. LIP: LongWord;
  3911. begin
  3912. LIP := IPv4ToDWord(AAddr, LErr);
  3913. if LErr then begin
  3914. Result := '';
  3915. end else begin
  3916. Result := MakeDWordIntoIPv4Address(LIP);
  3917. end;
  3918. end;
  3919. function MakeCanonicalIPv6Address(const AAddr: string): string;
  3920. // return an empty string if the address is invalid,
  3921. // for easy checking if its an address or not.
  3922. var
  3923. p, i: Integer;
  3924. {$IFDEF BYTE_COMPARE_SETS}
  3925. dots, colons: Byte;
  3926. {$ELSE}
  3927. dots, colons: Integer;
  3928. {$ENDIF}
  3929. colonpos: array[1..8] of Integer;
  3930. dotpos: array[1..3] of Integer;
  3931. LAddr: string;
  3932. num: Integer;
  3933. haddoublecolon: boolean;
  3934. fillzeros: Integer;
  3935. begin
  3936. Result := ''; // error
  3937. LAddr := AAddr;
  3938. if Length(LAddr) = 0 then begin
  3939. Exit;
  3940. end;
  3941. if TextStartsWith(LAddr, ':') then begin
  3942. LAddr := '0' + LAddr;
  3943. end;
  3944. if TextEndsWith(LAddr, ':') then begin
  3945. LAddr := LAddr + '0';
  3946. end;
  3947. dots := 0;
  3948. colons := 0;
  3949. for p := 1 to Length(LAddr) do begin
  3950. case LAddr[p] of
  3951. '.': begin
  3952. Inc(dots);
  3953. if dots < 4 then begin
  3954. dotpos[dots] := p;
  3955. end else begin
  3956. Exit; // error in address
  3957. end;
  3958. end;
  3959. ':': begin
  3960. Inc(colons);
  3961. if colons < 8 then begin
  3962. colonpos[colons] := p;
  3963. end else begin
  3964. Exit; // error in address
  3965. end;
  3966. end;
  3967. 'a'..'f',
  3968. 'A'..'F': if dots > 0 then Exit;
  3969. // allow only decimal stuff within dotted portion, ignore otherwise
  3970. '0'..'9': ; // do nothing
  3971. else
  3972. Exit; // error in address
  3973. end; // case
  3974. end; // for
  3975. if not (dots in [0,3]) then begin
  3976. Exit; // you have to write 0 or 3 dots...
  3977. end;
  3978. if dots = 3 then begin
  3979. if not (colons in [2..6]) then begin
  3980. Exit; // must not have 7 colons if we have dots
  3981. end;
  3982. if colonpos[colons] > dotpos[1] then begin
  3983. Exit; // x:x:x.x:x:x is not valid
  3984. end;
  3985. end else begin
  3986. if not (colons in [2..7]) then begin
  3987. Exit; // must at least have two colons
  3988. end;
  3989. end;
  3990. // now start :-)
  3991. num := IndyStrToInt('$'+Copy(LAddr, 1, colonpos[1]-1), -1);
  3992. if (num < 0) or (num > 65535) then begin
  3993. Exit; // huh? odd number...
  3994. end;
  3995. Result := IntToHex(num, 1) + ':';
  3996. haddoublecolon := False;
  3997. for p := 2 to colons do begin
  3998. if colonpos[p - 1] = colonpos[p]-1 then begin
  3999. if haddoublecolon then begin
  4000. Result := '';
  4001. Exit; // only a single double-dot allowed!
  4002. end;
  4003. haddoublecolon := True;
  4004. fillzeros := 8 - colons;
  4005. if dots > 0 then begin
  4006. Dec(fillzeros);
  4007. end;
  4008. for i := 1 to fillzeros do begin
  4009. Result := Result + '0:'; {do not localize}
  4010. end;
  4011. end else begin
  4012. num := IndyStrToInt('$' + Copy(LAddr, colonpos[p - 1] + 1, colonpos[p] - colonpos[p - 1] - 1), -1);
  4013. if (num < 0) or (num > 65535) then begin
  4014. Result := '';
  4015. Exit; // huh? odd number...
  4016. end;
  4017. Result := Result + IntToHex(num,1) + ':';
  4018. end;
  4019. end; // end of colon separated part
  4020. if dots = 0 then begin
  4021. num := IndyStrToInt('$' + Copy(LAddr, colonpos[colons] + 1, MaxInt), -1);
  4022. if (num < 0) or (num > 65535) then begin
  4023. Result := '';
  4024. Exit; // huh? odd number...
  4025. end;
  4026. Result := Result + IntToHex(num,1) + ':';
  4027. end;
  4028. if dots > 0 then begin
  4029. num := IndyStrToInt(Copy(LAddr, colonpos[colons] + 1, dotpos[1] - colonpos[colons] -1),-1);
  4030. if (num < 0) or (num > 255) then begin
  4031. Result := '';
  4032. Exit;
  4033. end;
  4034. Result := Result + IntToHex(num, 2);
  4035. num := IndyStrToInt(Copy(LAddr, dotpos[1]+1, dotpos[2]-dotpos[1]-1),-1);
  4036. if (num < 0) or (num > 255) then begin
  4037. Result := '';
  4038. Exit;
  4039. end;
  4040. Result := Result + IntToHex(num, 2) + ':';
  4041. num := IndyStrToInt(Copy(LAddr, dotpos[2] + 1, dotpos[3] - dotpos[2] -1),-1);
  4042. if (num < 0) or (num > 255) then begin
  4043. Result := '';
  4044. Exit;
  4045. end;
  4046. Result := Result + IntToHex(num, 2);
  4047. num := IndyStrToInt(Copy(LAddr, dotpos[3] + 1, 3), -1);
  4048. if (num < 0) or (num > 255) then begin
  4049. Result := '';
  4050. Exit;
  4051. end;
  4052. Result := Result + IntToHex(num, 2) + ':';
  4053. end;
  4054. SetLength(Result, Length(Result) - 1);
  4055. end;
  4056. procedure IPv6ToIdIPv6Address(const AIPAddress: String; var VAddress: TIdIPv6Address);
  4057. {$IFDEF USE_INLINE}inline;{$ENDIF}
  4058. var
  4059. LErr: Boolean;
  4060. begin
  4061. IPv6ToIdIPv6Address(AIPAddress, VAddress, LErr);
  4062. if LErr then begin
  4063. raise EIdInvalidIPv6Address.CreateFmt(RSInvalidIPv6Address, [AIPAddress]);
  4064. end;
  4065. end;
  4066. procedure IPv6ToIdIPv6Address(const AIPAddress: String; var VAddress: TIdIPv6Address; var VErr: Boolean);
  4067. var
  4068. LAddress: string;
  4069. I: Integer;
  4070. begin
  4071. LAddress := MakeCanonicalIPv6Address(AIPAddress);
  4072. VErr := (LAddress = '');
  4073. if VErr then begin
  4074. Exit;
  4075. end;
  4076. for I := 0 to 7 do begin
  4077. VAddress[I] := IndyStrToInt('$' + Fetch(LAddress,':'), 0);
  4078. end;
  4079. end;
  4080. function IndyMax(const AValueOne, AValueTwo: Int64): Int64;
  4081. {$IFDEF USE_INLINE}inline;{$ENDIF}
  4082. begin
  4083. if AValueOne < AValueTwo then begin
  4084. Result := AValueTwo;
  4085. end else begin
  4086. Result := AValueOne;
  4087. end;
  4088. end;
  4089. function IndyMax(const AValueOne, AValueTwo: LongInt): LongInt;
  4090. {$IFDEF USE_INLINE}inline;{$ENDIF}
  4091. begin
  4092. if AValueOne < AValueTwo then begin
  4093. Result := AValueTwo;
  4094. end else begin
  4095. Result := AValueOne;
  4096. end;
  4097. end;
  4098. function IndyMax(const AValueOne, AValueTwo: Word): Word;
  4099. {$IFDEF USE_INLINE}inline;{$ENDIF}
  4100. begin
  4101. if AValueOne < AValueTwo then begin
  4102. Result := AValueTwo;
  4103. end else begin
  4104. Result := AValueOne;
  4105. end;
  4106. end;
  4107. {$IFNDEF DOTNET}
  4108. // TODO: validate this with Unicode data
  4109. function MemoryPos(const ASubStr: string; MemBuff: PChar; MemorySize: Integer): Integer;
  4110. var
  4111. LSearchLength: Integer;
  4112. LS1: Integer;
  4113. LChar: Char;
  4114. LPS, LPM: PChar;
  4115. begin
  4116. LSearchLength := Length(ASubStr);
  4117. if (LSearchLength = 0) or (LSearchLength > (MemorySize * SizeOf(Char))) then begin
  4118. Result := 0;
  4119. Exit;
  4120. end;
  4121. LChar := PChar(Pointer(ASubStr))^; //first char
  4122. LPS := PChar(Pointer(ASubStr))+1;//tail string
  4123. LPM := MemBuff;
  4124. LS1 := LSearchLength-1;
  4125. LSearchLength := MemorySize-LS1;//MemorySize-LS+1
  4126. if LS1 = 0 then begin //optimization for freq used LF
  4127. while LSearchLength > 0 do begin
  4128. if LPM^ = LChar then begin
  4129. Result := LPM-MemBuff + 1;
  4130. Exit;
  4131. end;
  4132. Inc(LPM);
  4133. Dec(LSearchLength);
  4134. end;//while
  4135. end else begin
  4136. while LSearchLength > 0 do begin
  4137. if LPM^ = LChar then begin
  4138. Inc(LPM);
  4139. if CompareMem(LPM, LPS, LS1 * SizeOf(Char)) then begin
  4140. Result := LPM - MemBuff;
  4141. Exit;
  4142. end;
  4143. end else begin
  4144. Inc(LPM);
  4145. end;
  4146. Dec(LSearchLength);
  4147. end;
  4148. end;
  4149. Result := 0;
  4150. end;
  4151. {$ENDIF}
  4152. function IndyMin(const AValueOne, AValueTwo: LongInt): LongInt;
  4153. {$IFDEF USE_INLINE}inline;{$ENDIF}
  4154. begin
  4155. if AValueOne > AValueTwo then begin
  4156. Result := AValueTwo;
  4157. end else begin
  4158. Result := AValueOne;
  4159. end;
  4160. end;
  4161. function IndyMin(const AValueOne, AValueTwo: Int64): Int64;
  4162. {$IFDEF USE_INLINE}inline;{$ENDIF}
  4163. begin
  4164. if AValueOne > AValueTwo then begin
  4165. Result := AValueTwo;
  4166. end else begin
  4167. Result := AValueOne;
  4168. end;
  4169. end;
  4170. function IndyMin(const AValueOne, AValueTwo: Word): Word;
  4171. {$IFDEF USE_INLINE}inline;{$ENDIF}
  4172. begin
  4173. if AValueOne > AValueTwo then begin
  4174. Result := AValueTwo;
  4175. end else begin
  4176. Result := AValueOne;
  4177. end;
  4178. end;
  4179. function PosIdx(const ASubStr, AStr: string; AStartPos: LongWord): LongWord;
  4180. {$IFDEF DOTNET}
  4181. {$IFDEF USE_INLINE}inline;{$ENDIF}
  4182. {$ELSE}
  4183. // use best register allocation on Win32
  4184. function FindStr(ALStartPos, EndPos: LongWord; StartChar: Char; const ALStr: string): LongWord;
  4185. begin
  4186. for Result := ALStartPos to EndPos do begin
  4187. if ALStr[Result] = StartChar then begin
  4188. Exit;
  4189. end;
  4190. end;
  4191. Result := 0;
  4192. end;
  4193. // use best register allocation on Win32
  4194. function FindNextStr(ALStartPos, EndPos: LongWord; const ALStr, ALSubStr: string): LongWord;
  4195. begin
  4196. for Result := ALStartPos + 1 to EndPos do begin
  4197. if ALStr[Result] <> ALSubStr[Result - ALStartPos + 1] then begin
  4198. Exit;
  4199. end;
  4200. end;
  4201. Result := 0;
  4202. end;
  4203. var
  4204. StartChar: Char;
  4205. LenSubStr, LenStr: LongWord;
  4206. EndPos: LongWord;
  4207. {$ENDIF}
  4208. begin
  4209. if AStartPos = 0 then begin
  4210. AStartPos := 1;
  4211. end;
  4212. {$IFDEF DOTNET}
  4213. Result := AStr.IndexOf(ASubStr, AStartPos-1) + 1;
  4214. {$ELSE}
  4215. Result := 0;
  4216. LenSubStr := Length(ASubStr);
  4217. LenStr := Length(AStr);
  4218. if (LenSubStr = 0) or (AStr = '') or (LenSubStr > (LenStr - (AStartPos - 1))) then begin
  4219. Exit;
  4220. end;
  4221. StartChar := ASubStr[1];
  4222. EndPos := LenStr - LenSubStr + 1;
  4223. if LenSubStr = 1 then begin
  4224. Result := FindStr(AStartPos, EndPos, StartChar, AStr)
  4225. end else
  4226. begin
  4227. repeat
  4228. Result := FindStr(AStartPos, EndPos, StartChar, AStr);
  4229. if Result = 0 then begin
  4230. Break;
  4231. end;
  4232. AStartPos := Result;
  4233. Result := FindNextStr(Result, AStartPos + LenSubStr - 1, AStr, ASubStr);
  4234. if Result = 0 then
  4235. begin
  4236. Result := AStartPos;
  4237. Exit;
  4238. end;
  4239. Inc(AStartPos);
  4240. until False;
  4241. end;
  4242. {$ENDIF}
  4243. end;
  4244. function SBPos(const Substr, S: string): LongInt;
  4245. {$IFDEF USE_INLINE}inline;{$ENDIF}
  4246. begin
  4247. // Necessary because of "Compiler magic"
  4248. Result := Pos(Substr, S);
  4249. end;
  4250. {$IFNDEF DOTNET}
  4251. function SBStrScan(Str: PChar; Chr: Char): PChar;
  4252. {$IFDEF USE_INLINE}inline;{$ENDIF}
  4253. begin
  4254. Result := SysUtils.StrScan(Str, Chr);
  4255. end;
  4256. {$ENDIF}
  4257. {$IFNDEF DOTNET}
  4258. //Don't rename this back to AnsiPos because that conceals a symbol in Windows
  4259. function InternalAnsiPos(const Substr, S: string): LongInt;
  4260. {$IFDEF USE_INLINE}inline;{$ENDIF}
  4261. begin
  4262. Result := SysUtils.AnsiPos(Substr, S);
  4263. end;
  4264. function InternalAnsiStrScan(Str: PChar; Chr: Char): PChar;
  4265. {$IFDEF USE_INLINE}inline;{$ENDIF}
  4266. begin
  4267. Result := SysUtils.AnsiStrScan(Str, Chr);
  4268. end;
  4269. {$ENDIF}
  4270. procedure IndySetThreadPriority(AThread: TThread; const APriority: TIdThreadPriority;
  4271. const APolicy: Integer = -MaxInt);
  4272. {$IFDEF USE_INLINE}inline;{$ENDIF}
  4273. begin
  4274. {$IFDEF UNIX}
  4275. {$IFDEF KYLIXCOMPAT}
  4276. {$IFDEF INT_THREAD_PRIORITY}
  4277. // Linux only allows root to adjust thread priorities, so we just ignore this call in Linux?
  4278. // actually, why not allow it if root
  4279. // and also allow setting *down* threadpriority (anyone can do that)
  4280. // note that priority is called "niceness" and positive is lower priority
  4281. if (getpriority(PRIO_PROCESS, 0) < APriority) or (geteuid = 0) then begin
  4282. setpriority(PRIO_PROCESS, 0, APriority);
  4283. end;
  4284. {$ELSE}
  4285. AThread.Priority := APriority;
  4286. {$ENDIF}
  4287. {$ENDIF}
  4288. {$IFDEF USE_BASEUNIX}
  4289. // Linux only allows root to adjust thread priorities, so we just ingnore this call in Linux?
  4290. // actually, why not allow it if root
  4291. // and also allow setting *down* threadpriority (anyone can do that)
  4292. // note that priority is called "niceness" and positive is lower priority
  4293. if (fpgetpriority(PRIO_PROCESS, 0) < cint(APriority)) or (fpgeteuid = 0) then begin
  4294. fpsetpriority(PRIO_PROCESS, 0, cint(APriority));
  4295. end;
  4296. {$ENDIF}
  4297. {$ENDIF}
  4298. {$IFDEF WINDOWS}
  4299. AThread.Priority := APriority;
  4300. {$ENDIF}
  4301. {$IFDEF DOTNET}
  4302. AThread.Priority := APriority;
  4303. {$ENDIF}
  4304. end;
  4305. procedure IndySleep(ATime: LongWord);
  4306. {$IFDEF USE_VCL_POSIX}
  4307. {$IFDEF USE_INLINE}inline;{$ENDIF}
  4308. var
  4309. LTime: TimeVal;
  4310. {$ELSE}
  4311. {$IFNDEF UNIX}
  4312. {$IFDEF USE_INLINE}inline;{$ENDIF}
  4313. {$ELSE}
  4314. var
  4315. LTime: TTimeVal;
  4316. {$ENDIF}
  4317. {$ENDIF}
  4318. begin
  4319. {$IFDEF UNIX}
  4320. // *nix: Is there are reason for not using nanosleep?
  4321. // what if the user just calls sleep? without doing anything...
  4322. // cannot use GStack.WSSelectRead(nil, ATime)
  4323. // since no readsocketlist exists to get the fdset
  4324. LTime.tv_sec := ATime div 1000;
  4325. LTime.tv_usec := (ATime mod 1000) * 1000;
  4326. {$IFDEF USE_VCL_POSIX}
  4327. select( 0, nil, nil, nil, @LTime);
  4328. {$ENDIF}
  4329. {$IFDEF KYLIXCOMPAT}
  4330. Libc.Select(0, nil, nil, nil, @LTime);
  4331. {$ENDIF}
  4332. {$IFDEF USE_BASEUNIX}
  4333. fpSelect(0, nil, nil, nil, @LTime);
  4334. {$ENDIF}
  4335. {$ENDIF}
  4336. {$IFDEF WINDOWS}
  4337. Windows.Sleep(ATime);
  4338. {$ENDIF}
  4339. {$IFDEF DOTNET}
  4340. Thread.Sleep(ATime);
  4341. {$ENDIF}
  4342. end;
  4343. procedure SplitColumnsNoTrim(const AData: string; AStrings: TStrings; const ADelim: string);
  4344. var
  4345. i: Integer;
  4346. LDelim: Integer; //delim len
  4347. LLeft: string;
  4348. {$IFDEF DOTNET}
  4349. LLastPos: Integer;
  4350. {$ELSE}
  4351. LLastPos: PtrInt;
  4352. //note that we use PtrInt instead of Integer because in FPC,
  4353. //you can't assume a pointer will be exactly 4 bytes. It could be 8 or possibly
  4354. //2 bytes. Remember that that supports operating systems with versions for different
  4355. //architectures
  4356. {$ENDIF}
  4357. begin
  4358. Assert(Assigned(AStrings));
  4359. AStrings.Clear;
  4360. LDelim := Length(ADelim);
  4361. LLastPos := 1;
  4362. i := Pos(ADelim, AData);
  4363. while I > 0 do begin
  4364. LLeft := Copy(AData, LLastPos, I - LLastPos); //'abc d' len:=i(=4)-1 {Do not Localize}
  4365. if LLeft <> '' then begin {Do not Localize}
  4366. {$IFDEF DOTNET}
  4367. AStrings.AddObject(LLeft, TObject(LLastPos));
  4368. {$ELSE}
  4369. AStrings.AddObject(LLeft, TObject(PtrInt(LLastPos)));
  4370. {$ENDIF}
  4371. end;
  4372. LLastPos := I + LDelim; //first char after Delim
  4373. i := PosIdx(ADelim, AData, LLastPos);
  4374. end;
  4375. if LLastPos <= Length(AData) then begin
  4376. {$IFDEF DOTNET}
  4377. AStrings.AddObject(Copy(AData, LLastPos, MaxInt), TObject(LLastPos));
  4378. {$ELSE}
  4379. AStrings.AddObject(Copy(AData, LLastPos, MaxInt), TObject(PtrInt(LLastPos)));
  4380. {$ENDIF}
  4381. end;
  4382. end;
  4383. {$IFDEF DOTNET}
  4384. procedure SetThreadName(const AName: string; AThread: System.Threading.Thread = nil);
  4385. begin
  4386. if AThread = nil then begin
  4387. AThread := System.Threading.Thread.CurrentThread;
  4388. end;
  4389. // cannot rename a previously-named thread
  4390. if AThread.Name = nil then begin
  4391. AThread.Name := AName;
  4392. end;
  4393. end;
  4394. {$ELSE}
  4395. procedure SetThreadName(const AName: string; AThreadID: LongWord = $FFFFFFFF);
  4396. {$IFDEF HAS_NAMED_THREADS}
  4397. {$IFDEF HAS_TThread_NameThreadForDebugging}
  4398. {$IFDEF USE_INLINE}inline;{$ENDIF}
  4399. {$ELSE}
  4400. {$IFDEF WINDOWS}
  4401. const
  4402. MS_VC_EXCEPTION = $406D1388;
  4403. type
  4404. TThreadNameInfo = record
  4405. RecType: LongWord; // Must be 0x1000
  4406. Name: PAnsiChar; // Pointer to name (in user address space)
  4407. ThreadID: LongWord; // Thread ID (-1 indicates caller thread)
  4408. Flags: LongWord; // Reserved for future use. Must be zero
  4409. end;
  4410. var
  4411. LThreadNameInfo: TThreadNameInfo;
  4412. {$ENDIF}
  4413. {$ENDIF}
  4414. {$ENDIF}
  4415. begin
  4416. {$IFDEF HAS_NAMED_THREADS}
  4417. {$IFDEF HAS_TThread_NameThreadForDebugging}
  4418. TThread.NameThreadForDebugging(AnsiString(AName), AThreadID);
  4419. {$ELSE}
  4420. {$IFDEF WINDOWS}
  4421. with LThreadNameInfo do begin
  4422. RecType := $1000;
  4423. Name := {$IFDEF STRING_IS_UNICODE}PAnsiChar(AnsiString(AName)){$ELSE}PChar(AName){$ENDIF};
  4424. ThreadID := AThreadID;
  4425. Flags := 0;
  4426. end;
  4427. try
  4428. // This is a wierdo Windows way to pass the info in
  4429. RaiseException(MS_VC_EXCEPTION, 0, SizeOf(LThreadNameInfo) div SizeOf(LongWord),
  4430. PDWord(@LThreadNameInfo));
  4431. except
  4432. end;
  4433. {$ENDIF}
  4434. {$ENDIF}
  4435. {$ELSE}
  4436. // Do nothing. No support in this compiler for it.
  4437. {$ENDIF}
  4438. end;
  4439. {$ENDIF}
  4440. procedure SplitColumns(const AData: string; AStrings: TStrings; const ADelim: string);
  4441. var
  4442. i: Integer;
  4443. LData: string;
  4444. LDelim: Integer; //delim len
  4445. LLeft: string;
  4446. LLastPos: Integer;
  4447. LLeadingSpaceCnt: Integer;
  4448. Begin
  4449. Assert(Assigned(AStrings));
  4450. AStrings.Clear;
  4451. LDelim := Length(ADelim);
  4452. LLastPos := 1;
  4453. LData := Trim(AData);
  4454. if LData = '' then begin //if WhiteStr
  4455. Exit;
  4456. end;
  4457. LLeadingSpaceCnt := 0;
  4458. while AData[LLeadingSpaceCnt + 1] <= #32 do begin
  4459. Inc(LLeadingSpaceCnt);
  4460. end;
  4461. i := Pos(ADelim, LData);
  4462. while I > 0 do begin
  4463. LLeft := Copy(LData, LLastPos, I - LLastPos); //'abc d' len:=i(=4)-1 {Do not Localize}
  4464. if LLeft > '' then begin {Do not Localize}
  4465. AStrings.AddObject(Trim(LLeft), TObject(LLastPos + LLeadingSpaceCnt));
  4466. end;
  4467. LLastPos := I + LDelim; //first char after Delim
  4468. i := PosIdx(ADelim, LData, LLastPos);
  4469. end;//while found
  4470. if LLastPos <= Length(LData) then begin
  4471. AStrings.AddObject(Trim(Copy(LData, LLastPos, MaxInt)), TObject(LLastPos + LLeadingSpaceCnt));
  4472. end;
  4473. end;
  4474. {$IFDEF DOTNET}
  4475. {$IFNDEF DOTNET_2_OR_ABOVE}
  4476. { TEvent }
  4477. constructor TEvent.Create(EventAttributes: IntPtr; ManualReset, InitialState: Boolean; const Name: string);
  4478. begin
  4479. inherited Create;
  4480. // Name not used
  4481. if ManualReset then begin
  4482. FEvent := ManualResetEvent.Create(InitialState);
  4483. end else begin
  4484. FEvent := AutoResetEvent.Create(InitialState);
  4485. end;
  4486. end;
  4487. constructor TEvent.Create;
  4488. begin
  4489. Create(nil, True, False, ''); {Do not Localize}
  4490. end;
  4491. destructor TEvent.Destroy;
  4492. begin
  4493. if Assigned(FEvent) then begin
  4494. FEvent.Close;
  4495. end;
  4496. FreeAndNil(FEvent);
  4497. inherited Destroy;
  4498. end;
  4499. procedure TEvent.SetEvent;
  4500. begin
  4501. if FEvent is ManualResetEvent then begin
  4502. ManualResetEvent(FEvent).&Set;
  4503. end else begin
  4504. AutoResetEvent(FEvent).&Set;
  4505. end;
  4506. end;
  4507. procedure TEvent.ResetEvent;
  4508. begin
  4509. if FEvent is ManualResetEvent then begin
  4510. ManualResetEvent(FEvent).Reset;
  4511. end else begin
  4512. AutoResetEvent(FEvent).Reset;
  4513. end;
  4514. end;
  4515. function TEvent.WaitFor(Timeout: LongWord): TWaitResult;
  4516. var
  4517. Passed: Boolean;
  4518. begin
  4519. try
  4520. if Timeout = INFINITE then begin
  4521. Passed := FEvent.WaitOne;
  4522. end else begin
  4523. Passed := FEvent.WaitOne(Timeout, True);
  4524. end;
  4525. if Passed then begin
  4526. Result := wrSignaled;
  4527. end else begin
  4528. Result := wrTimeout;
  4529. end;
  4530. except
  4531. Result := wrError;
  4532. end;
  4533. end;
  4534. { TCriticalSection }
  4535. procedure TCriticalSection.Acquire;
  4536. begin
  4537. Enter;
  4538. end;
  4539. procedure TCriticalSection.Release;
  4540. begin
  4541. Leave;
  4542. end;
  4543. function TCriticalSection.TryEnter: Boolean;
  4544. begin
  4545. Result := System.Threading.Monitor.TryEnter(Self);
  4546. end;
  4547. procedure TCriticalSection.Enter;
  4548. begin
  4549. System.Threading.Monitor.Enter(Self);
  4550. end;
  4551. procedure TCriticalSection.Leave;
  4552. begin
  4553. System.Threading.Monitor.Exit(Self);
  4554. end;
  4555. {$ENDIF}
  4556. {$ENDIF}
  4557. { TIdLocalEvent }
  4558. constructor TIdLocalEvent.Create(const AInitialState: Boolean = False; const AManualReset: Boolean = False);
  4559. begin
  4560. inherited Create(nil, AManualReset, AInitialState, ''); {Do not Localize}
  4561. end;
  4562. function TIdLocalEvent.WaitForEver: TWaitResult;
  4563. begin
  4564. Result := WaitFor(Infinite);
  4565. end;
  4566. { TIdList }
  4567. {$IFNDEF HAS_TList_Assign}
  4568. procedure TIdExtList.Assign(AList: TList);
  4569. var
  4570. I: Integer;
  4571. begin
  4572. Clear;
  4573. Capacity := AList.Capacity;
  4574. for I := 0 to AList.Count - 1 do
  4575. Add(AList.Items[I]);
  4576. end;
  4577. {$ENDIF}
  4578. procedure ToDo(const AMsg: string);
  4579. {$IFDEF USE_INLINE}inline;{$ENDIF}
  4580. begin
  4581. EIdException.Toss(AMsg);
  4582. end;
  4583. // RLebeau: the following three functions are utility functions
  4584. // that determine the usable amount of data in various buffer types.
  4585. // There are many operations in Indy that allow the user to specify
  4586. // data sizes, or to have Indy calculate it. So these functions
  4587. // help reduce code duplication.
  4588. function IndyLength(const ABuffer: String; const ALength: Integer = -1; const AIndex: Integer = 1): Integer;
  4589. {$IFDEF USE_INLINE}inline;{$ENDIF}
  4590. var
  4591. LAvailable: Integer;
  4592. begin
  4593. Assert(AIndex >= 1);
  4594. LAvailable := IndyMax(Length(ABuffer)-AIndex+1, 0);
  4595. if ALength < 0 then begin
  4596. Result := LAvailable;
  4597. end else begin
  4598. Result := IndyMin(LAvailable, ALength);
  4599. end;
  4600. end;
  4601. function IndyLength(const ABuffer: TIdBytes; const ALength: Integer = -1; const AIndex: Integer = 0): Integer;
  4602. {$IFDEF USE_INLINE}inline;{$ENDIF}
  4603. var
  4604. LAvailable: Integer;
  4605. begin
  4606. Assert(AIndex >= 0);
  4607. LAvailable := IndyMax(Length(ABuffer)-AIndex, 0);
  4608. if ALength < 0 then begin
  4609. Result := LAvailable;
  4610. end else begin
  4611. Result := IndyMin(LAvailable, ALength);
  4612. end;
  4613. end;
  4614. function IndyLength(const ABuffer: TStream; const ALength: TIdStreamSize = -1): TIdStreamSize; overload;
  4615. {$IFDEF USE_INLINE}inline;{$ENDIF}
  4616. var
  4617. LAvailable: TIdStreamSize;
  4618. begin
  4619. LAvailable := IndyMax(ABuffer.Size - ABuffer.Position, 0);
  4620. if ALength < 0 then begin
  4621. Result := LAvailable;
  4622. end else begin
  4623. Result := IndyMin(LAvailable, ALength);
  4624. end;
  4625. end;
  4626. const
  4627. wdays: array[1..7] of string = ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'); {do not localize}
  4628. monthnames: array[1..12] of string = ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', {do not localize}
  4629. 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'); {do not localize}
  4630. {$IFDEF HAS_TFormatSettings}
  4631. //Delphi5 does not have TFormatSettings
  4632. //this should be changed to a singleton?
  4633. function GetEnglishSetting: TFormatSettings;
  4634. {$IFDEF USE_INLINE}inline;{$ENDIF}
  4635. begin
  4636. Result.CurrencyFormat := $00; // 0 = '$1'
  4637. Result.NegCurrFormat := $00; //0 = '($1)'
  4638. Result.CurrencyString := '$'; {do not localize}
  4639. Result.CurrencyDecimals := 2;
  4640. Result.ThousandSeparator := ','; {do not localize}
  4641. Result.DecimalSeparator := '.'; {do not localize}
  4642. Result.DateSeparator := '/'; {do not localize}
  4643. Result.ShortDateFormat := 'M/d/yyyy'; {do not localize}
  4644. Result.LongDateFormat := 'dddd, MMMM dd, yyyy'; {do not localize}
  4645. Result.TimeSeparator := ':'; {do not localize}
  4646. Result.TimeAMString := 'AM'; {do not localize}
  4647. Result.TimePMString := 'PM'; {do not localize}
  4648. Result.LongTimeFormat := 'h:mm:ss AMPM'; {do not localize}
  4649. Result.ShortTimeFormat := 'h:mm AMPM'; {do not localize}
  4650. Result.ShortMonthNames[1] := monthnames[1]; //'Jan';
  4651. Result.ShortMonthNames[2] := monthnames[2]; //'Feb';
  4652. Result.ShortMonthNames[3] := monthnames[3]; //'Mar';
  4653. Result.ShortMonthNames[4] := monthnames[4]; //'Apr';
  4654. Result.ShortMonthNames[5] := monthnames[5]; //'May';
  4655. Result.ShortMonthNames[6] := monthnames[6]; //'Jun';
  4656. Result.ShortMonthNames[7] := monthnames[7]; //'Jul';
  4657. Result.ShortMonthNames[8] := monthnames[8]; //'Aug';
  4658. Result.ShortMonthNames[9] := monthnames[9]; //'Sep';
  4659. Result.ShortMonthNames[10] := monthnames[10];// 'Oct';
  4660. Result.ShortMonthNames[11] := monthnames[11]; //'Nov';
  4661. Result.ShortMonthNames[12] := monthnames[12]; //'Dec';
  4662. Result.LongMonthNames[1] := 'January'; {do not localize}
  4663. Result.LongMonthNames[2] := 'February'; {do not localize}
  4664. Result.LongMonthNames[3] := 'March'; {do not localize}
  4665. Result.LongMonthNames[4] := 'April'; {do not localize}
  4666. Result.LongMonthNames[5] := 'May'; {do not localize}
  4667. Result.LongMonthNames[6] := 'June'; {do not localize}
  4668. Result.LongMonthNames[7] := 'July'; {do not localize}
  4669. Result.LongMonthNames[8] := 'August'; {do not localize}
  4670. Result.LongMonthNames[9] := 'September'; {do not localize}
  4671. Result.LongMonthNames[10] := 'October'; {do not localize}
  4672. Result.LongMonthNames[11] := 'November'; {do not localize}
  4673. Result.LongMonthNames[12] := 'December'; {do not localize}
  4674. Result.ShortDayNames[1] := wdays[1]; //'Sun';
  4675. Result.ShortDayNames[2] := wdays[2]; //'Mon';
  4676. Result.ShortDayNames[3] := wdays[3]; //'Tue';
  4677. Result.ShortDayNames[4] := wdays[4]; //'Wed';
  4678. Result.ShortDayNames[5] := wdays[5]; //'Thu';
  4679. Result.ShortDayNames[6] := wdays[6]; //'Fri';
  4680. Result.ShortDayNames[7] := wdays[7]; //'Sat';
  4681. Result.LongDayNames[1] := 'Sunday'; {do not localize}
  4682. Result.LongDayNames[2] := 'Monday'; {do not localize}
  4683. Result.LongDayNames[3] := 'Tuesday'; {do not localize}
  4684. Result.LongDayNames[4] := 'Wednesday'; {do not localize}
  4685. Result.LongDayNames[5] := 'Thursday'; {do not localize}
  4686. Result.LongDayNames[6] := 'Friday'; {do not localize}
  4687. Result.LongDayNames[7] := 'Saturday'; {do not localize}
  4688. Result.ListSeparator := ','; {do not localize}
  4689. end;
  4690. {$ENDIF}
  4691. // RLebeau 10/24/2008: In the RTM release of Delphi/C++Builder 2009, the
  4692. // overloaded version of SysUtils.Format() that has a TFormatSettings parameter
  4693. // has an internal bug that causes an EConvertError exception when UnicodeString
  4694. // parameters greater than 4094 characters are passed to it. Refer to QC #67934
  4695. // for details. The bug is fixed in 2009 Update 1. For RTM, call FormatBuf()
  4696. // directly to work around the problem...
  4697. function IndyFormat(const AFormat: string; const Args: array of const): string;
  4698. {$IFNDEF DOTNET}
  4699. {$IFDEF HAS_TFormatSettings}
  4700. var
  4701. EnglishFmt: TFormatSettings;
  4702. {$IFDEF BROKEN_FmtStr}
  4703. Len, BufLen: Integer;
  4704. Buffer: array[0..4095] of Char;
  4705. {$ENDIF}
  4706. {$ENDIF}
  4707. {$ENDIF}
  4708. begin
  4709. {$IFDEF DOTNET}
  4710. // RLebeau 10/29/09: temporary workaround until we figure out how to use
  4711. // SysUtils.FormatBuf() correctly under .NET in D2009 RTM...
  4712. Result := SysUtils.Format(AFormat, Args);
  4713. {$ELSE}
  4714. {$IFDEF HAS_TFormatSettings}
  4715. EnglishFmt := GetEnglishSetting;
  4716. {$IFDEF BROKEN_FmtStr}
  4717. BufLen := Length(Buffer);
  4718. if Length(AFormat) < (Length(Buffer) - (Length(Buffer) div 4)) then
  4719. begin
  4720. Len := SysUtils.FormatBuf(Buffer, Length(Buffer) - 1, Pointer(AFormat)^,
  4721. Length(AFormat), Args, EnglishFmt);
  4722. end else
  4723. begin
  4724. BufLen := Length(AFormat);
  4725. Len := BufLen;
  4726. end;
  4727. if Len >= BufLen - 1 then
  4728. begin
  4729. while Len >= BufLen - 1 do
  4730. begin
  4731. Inc(BufLen, BufLen);
  4732. Result := ''; // prevent copying of existing data, for speed
  4733. SetLength(Result, BufLen);
  4734. Len := SysUtils.FormatBuf(PChar(Result), BufLen - 1, Pointer(AFormat)^,
  4735. Length(AFormat), Args, EnglishFmt);
  4736. end;
  4737. SetLength(Result, Len);
  4738. end else
  4739. begin
  4740. SetString(Result, Buffer, Len);
  4741. end;
  4742. {$ELSE}
  4743. Result := SysUtils.Format(AFormat, Args, EnglishFmt);
  4744. {$ENDIF}
  4745. {$ELSE}
  4746. //Is there a way to get delphi5 to use locale in format? something like:
  4747. // SetThreadLocale(TheNewLocaleId);
  4748. // GetFormatSettings;
  4749. // Application.UpdateFormatSettings := False; //needed?
  4750. // format()
  4751. // set locale back to prior
  4752. Result := SysUtils.Format(AFormat, Args);
  4753. {$ENDIF}
  4754. {$ENDIF}
  4755. end;
  4756. function DateTimeGMTToHttpStr(const GMTValue: TDateTime) : String;
  4757. // should adhere to RFC 2616
  4758. var
  4759. wDay, wMonth, wYear: Word;
  4760. begin
  4761. DecodeDate(GMTValue, wYear, wMonth, wDay);
  4762. Result := IndyFormat('%s, %.2d %s %.4d %s %s', {do not localize}
  4763. [wdays[DayOfWeek(GMTValue)], wDay, monthnames[wMonth],
  4764. wYear, FormatDateTime('HH":"nn":"ss',GMTValue), 'GMT']); {do not localize}
  4765. end;
  4766. function DateTimeGMTToCookieStr(const GMTValue: TDateTime; const AUseNetscapeFmt: Boolean = True) : String;
  4767. var
  4768. wDay, wMonth, wYear: Word;
  4769. LDelim: Char;
  4770. begin
  4771. DecodeDate(GMTValue, wYear, wMonth, wDay);
  4772. // RLebeau: cookie draft-23 requires HTTP servers to format an Expires value as follows:
  4773. //
  4774. // Wdy, DD Mon YYYY HH:MM:SS GMT
  4775. //
  4776. // However, Netscape style formatting, which RFCs 2109 and 2965 allow
  4777. // (but draft-23 obsoletes), are more common:
  4778. //
  4779. // Wdy, DD-Mon-YY HH:MM:SS GMT (original)
  4780. // Wdy, DD-Mon-YYYY HH:MM:SS GMT (RFC 1123)
  4781. //
  4782. if AUseNetscapeFmt then begin
  4783. LDelim := '-'; {do not localize}
  4784. end else begin
  4785. LDelim := ' '; {do not localize}
  4786. end;
  4787. Result := IndyFormat('%s, %.2d%s%s%s%.4d %s %s', {do not localize}
  4788. [wdays[DayOfWeek(GMTValue)], wDay, LDelim, monthnames[wMonth], LDelim, wYear,
  4789. FormatDateTime('HH":"nn":"ss',GMTValue), 'GMT']); {do not localize}
  4790. end;
  4791. function LocalDateTimeToHttpStr(const Value: TDateTime) : String;
  4792. {$IFDEF USE_INLINE}inline;{$ENDIF}
  4793. begin
  4794. Result := DateTimeGMTToHttpStr(Value - OffsetFromUTC);
  4795. end;
  4796. function LocalDateTimeToCookieStr(const Value: TDateTime; const AUseNetscapeFmt: Boolean = True) : String;
  4797. {$IFDEF USE_INLINE}inline;{$ENDIF}
  4798. begin
  4799. Result := DateTimeGMTToCookieStr(Value - OffsetFromUTC, AUseNetscapeFmt);
  4800. end;
  4801. function DateTimeToInternetStr(const Value: TDateTime; const AUseGMTStr : Boolean = False) : String;
  4802. begin
  4803. Result := LocalDateTimeToGMT(Value, AUseGMTStr);
  4804. end;
  4805. {This should never be localized}
  4806. function LocalDateTimeToGMT(const Value: TDateTime; const AUseGMTStr: Boolean = False) : String;
  4807. var
  4808. wDay, wMonth, wYear: Word;
  4809. begin
  4810. DecodeDate(Value, wYear, wMonth, wDay);
  4811. Result := IndyFormat('%s, %d %s %d %s %s', {do not localize}
  4812. [wdays[DayOfWeek(Value)], wDay, monthnames[wMonth],
  4813. wYear, FormatDateTime('HH":"nn":"ss', Value), {do not localize}
  4814. UTCOffsetToStr(OffsetFromUTC, AUseGMTStr)]);
  4815. end;
  4816. function DateTimeToGmtOffSetStr(ADateTime: TDateTime; const AUseGMTStr: Boolean = False): string;
  4817. {$IFDEF USE_INLINE}inline;{$ENDIF}
  4818. begin
  4819. Result := UTCOffsetToStr(ADateTime, AUseGMTStr);
  4820. end;
  4821. function OffsetFromUTC: TDateTime;
  4822. {$IFDEF DOTNET}
  4823. {$IFDEF USE_INLINE}inline;{$ENDIF}
  4824. {$ELSE}
  4825. {$IFDEF WINDOWS}
  4826. var
  4827. iBias: Integer;
  4828. tmez: TTimeZoneInformation;
  4829. {$ENDIF}
  4830. {$IFDEF UNIX}
  4831. {$IFDEF USE_VCL_POSIX}
  4832. var
  4833. T : Time_t;
  4834. TV : TimeVal;
  4835. UT : tm;
  4836. {$ENDIF}
  4837. {$IFDEF USE_BASEUNIX}
  4838. var
  4839. timeval: TTimeVal;
  4840. timezone: TTimeZone;
  4841. {$ENDIF}
  4842. {$IFDEF KYLIXCOMPAT}
  4843. var
  4844. T: Time_T;
  4845. TV: TTimeVal;
  4846. UT: TUnixTime;
  4847. {$ENDIF}
  4848. {$ENDIF}
  4849. {$ENDIF}
  4850. begin
  4851. {$IFDEF UNIX}
  4852. {$IFDEF USE_VCL_POSIX}
  4853. {from http://edn.embarcadero.com/article/27890 }
  4854. gettimeofday(TV, nil);
  4855. T := TV.tv_sec;
  4856. localtime_r(T, UT);
  4857. Result := -1*(UT.tm_gmtoff / 60 / 60 / 24);
  4858. {$ENDIF}
  4859. {$IFDEF USE_BASEUNIX}
  4860. fpGetTimeOfDay (@TimeVal, @TimeZone);
  4861. Result := -1 * (timezone.tz_minuteswest /60 / 60 / 24)
  4862. {$ENDIF}
  4863. {$IFDEF KYLIXCOMPAT}
  4864. {from http://edn.embarcadero.com/article/27890 }
  4865. gettimeofday(TV, nil);
  4866. T := TV.tv_sec;
  4867. localtime_r(@T, UT);
  4868. Result := -1*(UT.__tm_gmtoff / 60 / 60 / 24);
  4869. {$ENDIF}
  4870. // __tm_gmtoff is the bias in seconds from the UTC to the current time.
  4871. // so I multiply by -1 to compensate for this.
  4872. {$ENDIF}
  4873. {$IFDEF DOTNET}
  4874. Result := System.Timezone.CurrentTimezone.GetUTCOffset(DateTime.FromOADate(Now)).TotalDays;
  4875. {$ENDIF}
  4876. {$IFDEF WINDOWS}
  4877. case GetTimeZoneInformation({$IFDEF WINCE}@{$ENDIF}tmez) of
  4878. TIME_ZONE_ID_INVALID :
  4879. raise EIdFailedToRetreiveTimeZoneInfo.Create(RSFailedTimeZoneInfo);
  4880. TIME_ZONE_ID_UNKNOWN :
  4881. iBias := tmez.Bias;
  4882. TIME_ZONE_ID_DAYLIGHT : begin
  4883. iBias := tmez.Bias;
  4884. if tmez.DaylightDate.wMonth <> 0 then begin
  4885. iBias := iBias + tmez.DaylightBias;
  4886. end;
  4887. end;
  4888. TIME_ZONE_ID_STANDARD : begin
  4889. iBias := tmez.Bias;
  4890. if tmez.StandardDate.wMonth <> 0 then begin
  4891. iBias := iBias + tmez.StandardBias;
  4892. end;
  4893. end
  4894. else
  4895. begin
  4896. raise EIdFailedToRetreiveTimeZoneInfo.Create(RSFailedTimeZoneInfo);
  4897. end;
  4898. end;
  4899. {We use ABS because EncodeTime will only accept positive values}
  4900. Result := EncodeTime(Abs(iBias) div 60, Abs(iBias) mod 60, 0, 0);
  4901. {The GetTimeZone function returns values oriented towards converting
  4902. a GMT time into a local time. We wish to do the opposite by returning
  4903. the difference between the local time and GMT. So I just make a positive
  4904. value negative and leave a negative value as positive}
  4905. if iBias > 0 then begin
  4906. Result := 0.0 - Result;
  4907. end;
  4908. {$ENDIF}
  4909. end;
  4910. function UTCOffsetToStr(const AOffset: TDateTime; const AUseGMTStr: Boolean = False): string;
  4911. var
  4912. AHour, AMin, ASec, AMSec: Word;
  4913. begin
  4914. if (AOffset = 0.0) and AUseGMTStr then
  4915. begin
  4916. Result := 'GMT'; {do not localize}
  4917. end else
  4918. begin
  4919. DecodeTime(AOffset, AHour, AMin, ASec, AMSec);
  4920. Result := IndyFormat(' %0.2d%0.2d', [AHour, AMin]); {do not localize}
  4921. if AOffset < 0.0 then begin
  4922. Result[1] := '-'; {do not localize}
  4923. end else begin
  4924. Result[1] := '+'; {do not localize}
  4925. end;
  4926. end;
  4927. end;
  4928. function IndyIncludeTrailingPathDelimiter(const S: string): string;
  4929. {$IFDEF USE_INLINE}inline;{$ENDIF}
  4930. begin
  4931. {$IFDEF HAS_SysUtils_IncludeExcludeTrailingPathDelimiter}
  4932. Result := SysUtils.IncludeTrailingPathDelimiter(S);
  4933. {$ELSE}
  4934. Result := SysUtils.IncludeTrailingBackslash(S);
  4935. {$ENDIF}
  4936. end;
  4937. function IndyExcludeTrailingPathDelimiter(const S: string): string;
  4938. {$IFDEF USE_INLINE}inline;{$ENDIF}
  4939. begin
  4940. {$IFDEF HAS_SysUtils_IncludeExcludeTrailingPathDelimiter}
  4941. Result := SysUtils.ExcludeTrailingPathDelimiter(S);
  4942. {$ELSE}
  4943. Result := SysUtils.ExcludeTrailingBackslash(S);
  4944. {$ENDIF}
  4945. end;
  4946. function StringsReplace(const S: String; const OldPattern, NewPattern: array of string): string;
  4947. var
  4948. i : Integer;
  4949. begin
  4950. // TODO: re-write this to not use StringReplace() in a loop anymore. If
  4951. // OldPattern contains multiple strings, a string appearing later in the
  4952. // list may be replaced multiple times by accident if it appears in the
  4953. // Result of an earlier string replacement.
  4954. Result := s;
  4955. for i := Low(OldPattern) to High(OldPattern) do begin
  4956. Result := StringReplace(Result, OldPattern[i], NewPattern[i], [rfReplaceAll]);
  4957. end;
  4958. end;
  4959. function ReplaceOnlyFirst(const S, OldPattern, NewPattern: string): string;
  4960. {$IFDEF USE_INLINE}inline;{$ENDIF}
  4961. begin
  4962. Result := SysUtils.StringReplace(s, OldPattern, NewPattern, []);
  4963. end;
  4964. function IndyStrToInt(const S: string): Integer;
  4965. {$IFDEF USE_INLINE}inline;{$ENDIF}
  4966. begin
  4967. Result := StrToInt(Trim(S));
  4968. end;
  4969. function IndyStrToInt(const S: string; ADefault: Integer): Integer;
  4970. {$IFDEF USE_INLINE}inline;{$ENDIF}
  4971. begin
  4972. Result := StrToIntDef(Trim(S), ADefault);
  4973. end;
  4974. function CompareDate(const D1, D2: TDateTime): Integer;
  4975. var
  4976. LTM1, LTM2 : TTimeStamp;
  4977. begin
  4978. LTM1 := DateTimeToTimeStamp(D1);
  4979. LTM2 := DateTimeToTimeStamp(D2);
  4980. if LTM1.Date = LTM2.Date then begin
  4981. if LTM1.Time < LTM2.Time then begin
  4982. Result := -1;
  4983. end
  4984. else if LTM1.Time > LTM2.Time then begin
  4985. Result := 1;
  4986. end
  4987. else begin
  4988. Result := 0;
  4989. end;
  4990. end
  4991. else if LTM1.Date > LTM2.Date then begin
  4992. Result := 1;
  4993. end
  4994. else begin
  4995. Result := -1;
  4996. end;
  4997. end;
  4998. function AddMSecToTime(const ADateTime: TDateTime; const AMSec: Integer): TDateTime;
  4999. {$IFDEF HAS_UNIT_DateUtils}
  5000. {$IFDEF USE_INLINE}inline;{$ENDIF}
  5001. {$ELSE}
  5002. var
  5003. LTM : TTimeStamp;
  5004. {$ENDIF}
  5005. begin
  5006. {$IFDEF HAS_UNIT_DateUtils}
  5007. Result := DateUtils.IncMilliSecond(ADateTime, AMSec);
  5008. {$ELSE}
  5009. LTM := DateTimeToTimeStamp(ADateTime);
  5010. LTM.Time := LTM.Time + AMSec;
  5011. Result := TimeStampToDateTime(LTM);
  5012. {$ENDIF}
  5013. end;
  5014. function IndyFileAge(const AFileName: string): TDateTime;
  5015. {$IFDEF HAS_2PARAM_FileAge}
  5016. {$IFDEF USE_INLINE}inline;{$ENDIF}
  5017. {$ELSE}
  5018. var
  5019. LAge: Integer;
  5020. {$ENDIF}
  5021. begin
  5022. {$IFDEF HAS_2PARAM_FileAge}
  5023. //single-parameter fileage is deprecated in d2006 and above
  5024. if not FileAge(AFileName, Result) then begin
  5025. Result := 0;
  5026. end;
  5027. {$ELSE}
  5028. LAge := SysUtils.FileAge(AFileName);
  5029. if LAge <> -1 then begin
  5030. Result := FileDateToDateTime(LAge);
  5031. end else begin
  5032. Result := 0.0;
  5033. end;
  5034. {$ENDIF}
  5035. end;
  5036. function IndyDirectoryExists(const ADirectory: string): Boolean;
  5037. {$IFDEF HAS_SysUtils_DirectoryExists}
  5038. {$IFDEF USE_INLINE}inline;{$ENDIF}
  5039. {$ELSE}
  5040. var
  5041. Code: Integer;
  5042. {$IFDEF UNICODE_BUT_STRING_IS_ANSI}
  5043. LWStr: WideString;
  5044. {$ENDIF}
  5045. {$ENDIF}
  5046. begin
  5047. {$IFDEF HAS_SysUtils_DirectoryExists}
  5048. Result := SysUtils.DirectoryExists(ADirectory);
  5049. {$ELSE}
  5050. // RLebeau 2/16/2006: Removed dependency on the FileCtrl unit
  5051. {$IFDEF UNICODE_BUT_STRING_IS_ANSI}
  5052. LWStr := WideString(ADirectory); // explicit convert to Unicode
  5053. Code := GetFileAttributes(PWideChar(LWStr));
  5054. {$ELSE}
  5055. Code := GetFileAttributes(PChar(ADirectory));
  5056. {$ENDIF}
  5057. Result := (Code <> -1) and ((Code and FILE_ATTRIBUTE_DIRECTORY) <> 0);
  5058. {$ENDIF}
  5059. end;
  5060. function IndyStrToInt64(const S: string; const ADefault: Int64): Int64;
  5061. {$IFDEF USE_INLINE}inline;{$ENDIF}
  5062. begin
  5063. Result := SysUtils.StrToInt64Def(Trim(S), ADefault);
  5064. end;
  5065. function IndyStrToInt64(const S: string): Int64;
  5066. {$IFDEF USE_INLINE}inline;{$ENDIF}
  5067. begin
  5068. Result := SysUtils.StrToInt64(Trim(S));
  5069. end;
  5070. function IndyStrToStreamSize(const S: string; const ADefault: TIdStreamSize): TIdStreamSize;
  5071. {$IFDEF USE_INLINE}inline;{$ENDIF}
  5072. begin
  5073. {$IFDEF STREAM_SIZE_64}
  5074. Result := IndyStrToInt64(S, ADefault);
  5075. {$ELSE}
  5076. Result := IndyStrToInt(S, ADefault);
  5077. {$ENDIF}
  5078. end;
  5079. function IndyStrToStreamSize(const S: string): TIdStreamSize;
  5080. {$IFDEF USE_INLINE}inline;{$ENDIF}
  5081. begin
  5082. {$IFDEF STREAM_SIZE_64}
  5083. Result := IndyStrToInt64(S);
  5084. {$ELSE}
  5085. Result := IndyStrToInt(S);
  5086. {$ENDIF}
  5087. end;
  5088. function ToBytes(const AValue: string; ADestEncoding: TIdTextEncoding = nil
  5089. {$IFDEF STRING_IS_ANSI}; ASrcEncoding: TIdTextEncoding = nil{$ENDIF}
  5090. ): TIdBytes; overload;
  5091. {$IFDEF USE_INLINE}inline;{$ENDIF}
  5092. begin
  5093. Result := ToBytes(AValue, -1, 1, ADestEncoding
  5094. {$IFDEF STRING_IS_ANSI}, ASrcEncoding{$ENDIF}
  5095. );
  5096. end;
  5097. function ToBytes(const AValue: string; const ALength: Integer; const AIndex: Integer = 1;
  5098. ADestEncoding: TIdTextEncoding = nil
  5099. {$IFDEF STRING_IS_ANSI}; ASrcEncoding: TIdTextEncoding = nil{$ENDIF}
  5100. ): TIdBytes; overload;
  5101. var
  5102. LLength: Integer;
  5103. {$IFDEF STRING_IS_ANSI}
  5104. LBytes: TIdBytes;
  5105. {$ENDIF}
  5106. begin
  5107. {$IFDEF STRING_IS_ANSI}
  5108. LBytes := nil; // keep the compiler happy
  5109. {$ENDIF}
  5110. LLength := IndyLength(AValue, ALength, AIndex);
  5111. if LLength > 0 then
  5112. begin
  5113. EnsureEncoding(ADestEncoding);
  5114. {$IFDEF STRING_IS_UNICODE}
  5115. SetLength(Result, ADestEncoding.GetByteCount(AValue, AIndex, LLength));
  5116. if Length(Result) > 0 then begin
  5117. ADestEncoding.GetBytes(AValue, AIndex, LLength, Result, 0);
  5118. end;
  5119. {$ELSE}
  5120. EnsureEncoding(ASrcEncoding, encOSDefault);
  5121. LBytes := RawToBytes(AValue[AIndex], LLength);
  5122. if ASrcEncoding <> ADestEncoding then begin
  5123. LBytes := TIdTextEncoding.Convert(ASrcEncoding, ADestEncoding, LBytes);
  5124. end;
  5125. Result := LBytes;
  5126. {$ENDIF}
  5127. end else begin
  5128. SetLength(Result, 0);
  5129. end;
  5130. end;
  5131. function ToBytes(const AValue: Char; ADestEncoding: TIdTextEncoding = nil
  5132. {$IFDEF STRING_IS_ANSI}; ASrcEncoding: TIdTextEncoding = nil{$ENDIF}
  5133. ): TIdBytes; overload;
  5134. var
  5135. {$IFDEF STRING_IS_UNICODE}
  5136. LChars: {$IFDEF DOTNET}array[0..0] of Char{$ELSE}TIdWideChars{$ENDIF};
  5137. {$ELSE}
  5138. LBytes: TIdBytes;
  5139. {$ENDIF}
  5140. begin
  5141. EnsureEncoding(ADestEncoding);
  5142. {$IFDEF STRING_IS_UNICODE}
  5143. {$IFNDEF DOTNET}
  5144. SetLength(LChars, 1);
  5145. {$ENDIF}
  5146. LChars[0] := AValue;
  5147. Result := ADestEncoding.GetBytes(LChars);
  5148. {$ELSE}
  5149. EnsureEncoding(ASrcEncoding, encOSDefault);
  5150. LBytes := RawToBytes(AValue, 1);
  5151. if ASrcEncoding <> ADestEncoding then begin
  5152. LBytes := TIdTextEncoding.Convert(ASrcEncoding, ADestEncoding, LBytes);
  5153. end;
  5154. Result := LBytes;
  5155. {$ENDIF}
  5156. end;
  5157. function ToBytes(const AValue: Int64): TIdBytes; overload;
  5158. {$IFDEF USE_INLINE}inline;{$ENDIF}
  5159. begin
  5160. {$IFDEF DOTNET}
  5161. Result := System.BitConverter.GetBytes(AValue);
  5162. {$ELSE}
  5163. SetLength(Result, SizeOf(Int64));
  5164. PInt64(@Result[0])^ := AValue;
  5165. {$ENDIF}
  5166. end;
  5167. function ToBytes(const AValue: LongInt): TIdBytes; overload;
  5168. {$IFDEF USE_INLINE}inline;{$ENDIF}
  5169. begin
  5170. {$IFDEF DOTNET}
  5171. Result := System.BitConverter.GetBytes(AValue);
  5172. {$ELSE}
  5173. SetLength(Result, SizeOf(LongInt));
  5174. PLongInt(@Result[0])^ := AValue;
  5175. {$ENDIF}
  5176. end;
  5177. function ToBytes(const AValue: LongWord): TIdBytes; overload;
  5178. {$IFDEF USE_INLINE}inline;{$ENDIF}
  5179. begin
  5180. {$IFDEF DOTNET}
  5181. Result := System.BitConverter.GetBytes(AValue);
  5182. {$ELSE}
  5183. SetLength(Result, SizeOf(LongWord));
  5184. PLongWord(@Result[0])^ := AValue;
  5185. {$ENDIF}
  5186. end;
  5187. function ToBytes(const AValue: Short): TIdBytes; overload;
  5188. {$IFDEF USE_INLINE}inline;{$ENDIF}
  5189. begin
  5190. {$IFDEF DOTNET}
  5191. Result := System.BitConverter.GetBytes(AValue);
  5192. {$ELSE}
  5193. SetLength(Result, SizeOf(SmallInt));
  5194. PSmallInt(@Result[0])^ := AValue;
  5195. {$ENDIF}
  5196. end;
  5197. function ToBytes(const AValue: Word): TIdBytes; overload;
  5198. {$IFDEF USE_INLINE}inline;{$ENDIF}
  5199. begin
  5200. {$IFDEF DOTNET}
  5201. Result := System.BitConverter.GetBytes(AValue);
  5202. {$ELSE}
  5203. SetLength(Result, SizeOf(Word));
  5204. PWord(@Result[0])^ := AValue;
  5205. {$ENDIF}
  5206. end;
  5207. function ToBytes(const AValue: Byte): TIdBytes; overload;
  5208. {$IFDEF USE_INLINE}inline;{$ENDIF}
  5209. begin
  5210. SetLength(Result, SizeOf(Byte));
  5211. Result[0] := AValue;
  5212. end;
  5213. function ToBytes(const AValue: TIdBytes; const ASize: Integer; const AIndex: Integer = 0): TIdBytes; overload;
  5214. {$IFDEF USE_INLINE}inline;{$ENDIF}
  5215. var
  5216. LSize: Integer;
  5217. begin
  5218. LSize := IndyLength(AValue, ASize, AIndex);
  5219. SetLength(Result, LSize);
  5220. if LSize > 0 then begin
  5221. CopyTIdBytes(AValue, AIndex, Result, 0, LSize);
  5222. end;
  5223. end;
  5224. {$IFNDEF DOTNET}
  5225. function RawToBytes(const AValue; const ASize: Integer): TIdBytes;
  5226. {$IFDEF USE_INLINE}inline;{$ENDIF}
  5227. begin
  5228. SetLength(Result, ASize);
  5229. if ASize > 0 then begin
  5230. Move(AValue, Result[0], ASize);
  5231. end;
  5232. end;
  5233. {$ENDIF}
  5234. procedure ToBytesF(var Bytes: TIdBytes; const AValue: Char; ADestEncoding: TIdTextEncoding = nil
  5235. {$IFDEF STRING_IS_ANSI}; ASrcEncoding: TIdTextEncoding = nil{$ENDIF}
  5236. );
  5237. {$IFDEF USE_INLINE}inline;{$ENDIF}
  5238. var
  5239. LChars: {$IFDEF DOTNET}array[0..0] of Char{$ELSE}TIdWideChars{$ENDIF};
  5240. begin
  5241. EnsureEncoding(ADestEncoding);
  5242. {$IFDEF STRING_IS_UNICODE}
  5243. {$IFNDEF DOTNET}
  5244. SetLength(LChars, 1);
  5245. {$ENDIF}
  5246. LChars[0] := AValue;
  5247. {$ELSE}
  5248. EnsureEncoding(ASrcEncoding, encOSDefault);
  5249. LChars := ASrcEncoding.GetChars(RawToBytes(AValue, 1)); // convert to Unicode
  5250. {$ENDIF}
  5251. Assert(Length(Bytes) >= ADestEncoding.GetByteCount(LChars));
  5252. ADestEncoding.GetBytes(LChars, 0, Length(LChars), Bytes, 0);
  5253. end;
  5254. procedure ToBytesF(var Bytes: TIdBytes; const AValue: LongInt);
  5255. {$IFDEF USE_INLINE}inline;{$ENDIF}
  5256. begin
  5257. Assert(Length(Bytes) >= SizeOf(AValue));
  5258. CopyTIdLongInt(AValue, Bytes, 0);
  5259. end;
  5260. procedure ToBytesF(var Bytes: TIdBytes; const AValue: Short);
  5261. {$IFDEF USE_INLINE}inline;{$ENDIF}
  5262. begin
  5263. Assert(Length(Bytes) >= SizeOf(AValue));
  5264. CopyTIdShort(AValue, Bytes, 0);
  5265. end;
  5266. procedure ToBytesF(var Bytes: TIdBytes; const AValue: Word);
  5267. {$IFDEF USE_INLINE}inline;{$ENDIF}
  5268. begin
  5269. Assert(Length(Bytes) >= SizeOf(AValue));
  5270. CopyTIdWord(AValue, Bytes, 0);
  5271. end;
  5272. procedure ToBytesF(var Bytes: TIdBytes; const AValue: Byte);
  5273. {$IFDEF USE_INLINE}inline;{$ENDIF}
  5274. begin
  5275. Assert(Length(Bytes) >= SizeOf(AValue));
  5276. Bytes[0] := AValue;
  5277. end;
  5278. procedure ToBytesF(var Bytes: TIdBytes; const AValue: LongWord);
  5279. {$IFDEF USE_INLINE}inline;{$ENDIF}
  5280. begin
  5281. Assert(Length(Bytes) >= SizeOf(AValue));
  5282. CopyTIdLongWord(AValue, Bytes, 0);
  5283. end;
  5284. procedure ToBytesF(var Bytes: TIdBytes; const AValue: Int64);
  5285. {$IFDEF USE_INLINE}inline;{$ENDIF}
  5286. begin
  5287. Assert(Length(Bytes) >= SizeOf(AValue));
  5288. CopyTIdInt64(AValue, Bytes, 0);
  5289. end;
  5290. procedure ToBytesF(var Bytes: TIdBytes; const AValue: TIdBytes; const ASize: Integer; const AIndex: Integer = 0);
  5291. {$IFDEF USE_INLINE}inline;{$ENDIF}
  5292. begin
  5293. Assert(Length(Bytes) >= ASize);
  5294. CopyTIdBytes(AValue, AIndex, Bytes, 0, ASize);
  5295. end;
  5296. {$IFNDEF DOTNET}
  5297. procedure RawToBytesF(var Bytes: TIdBytes; const AValue; const ASize: Integer);
  5298. {$IFDEF USE_INLINE}inline;{$ENDIF}
  5299. begin
  5300. Assert(Length(Bytes) >= ASize);
  5301. if ASize > 0 then begin
  5302. Move(AValue, Bytes[0], ASize);
  5303. end;
  5304. end;
  5305. {$ENDIF}
  5306. function BytesToChar(const AValue: TIdBytes; const AIndex: Integer = 0;
  5307. AByteEncoding: TIdTextEncoding = nil
  5308. {$IFDEF STRING_IS_ANSI}; ADestEncoding: TIdTextEncoding = nil{$ENDIF}
  5309. ): Char; overload;
  5310. {$IFDEF USE_INLINE}inline;{$ENDIF}
  5311. begin
  5312. BytesToChar(AValue, Result, AIndex, AByteEncoding{$IFDEF STRING_IS_ANSI}, ADestEncoding{$ENDIF});
  5313. end;
  5314. function BytesToChar(const AValue: TIdBytes; var VChar: Char; const AIndex: Integer = 0;
  5315. AByteEncoding: TIdTextEncoding = nil
  5316. {$IFDEF STRING_IS_ANSI}; ADestEncoding: TIdTextEncoding = nil{$ENDIF}
  5317. ): Integer; overload;
  5318. var
  5319. I, NumChars, NumBytes: Integer;
  5320. {$IFDEF DOTNET}
  5321. LChars: array[0..1] of Char;
  5322. {$ELSE}
  5323. LChars: TIdWideChars;
  5324. {$IFDEF STRING_IS_ANSI}
  5325. LWTmp: WideString;
  5326. LATmp: TIdBytes;
  5327. {$ENDIF}
  5328. {$ENDIF}
  5329. begin
  5330. Result := 0;
  5331. EnsureEncoding(AByteEncoding);
  5332. // 2 Chars to handle UTF-16 surrogates
  5333. NumBytes := IndyMin(IndyLength(AValue, -1, AIndex), AByteEncoding.GetMaxByteCount(2));
  5334. {$IFNDEF DOTNET}
  5335. SetLength(LChars, 2);
  5336. {$ENDIF}
  5337. NumChars := 0;
  5338. if NumBytes > 0 then
  5339. begin
  5340. for I := 1 to NumBytes do
  5341. begin
  5342. NumChars := AByteEncoding.GetChars(AValue, AIndex, I, LChars, 0);
  5343. Inc(Result);
  5344. if NumChars > 0 then begin
  5345. Break;
  5346. end;
  5347. end;
  5348. end;
  5349. {$IFDEF STRING_IS_UNICODE}
  5350. // RLebeau: if the bytes were decoded into surrogates, the second
  5351. // surrogate is lost here, as it can't be returned unless we cache
  5352. // it somewhere for the the next BytesToChar() call to retreive. Just
  5353. // raise an error for now. Users will have to update their code to
  5354. // read surrogates differently...
  5355. Assert(NumChars = 1);
  5356. VChar := LChars[0];
  5357. {$ELSE}
  5358. // RLebeau: since we can only return an AnsiChar here, let's convert
  5359. // the decoded characters, surrogates and all, into their Ansi
  5360. // representation. This will have the same problem as above if the
  5361. // conversion results in a multibyte character sequence...
  5362. EnsureEncoding(ADestEncoding, encOSDefault);
  5363. SetString(LWTmp, PWideChar(LChars), NumChars);
  5364. LATmp := ADestEncoding.GetBytes(LWTmp); // convert to Ansi
  5365. Assert(Length(LATmp) = 1);
  5366. VChar := Char(LATmp[0]);
  5367. {$ENDIF}
  5368. end;
  5369. function BytesToLongInt(const AValue: TIdBytes; const AIndex: Integer = 0): LongInt;
  5370. {$IFDEF USE_INLINE}inline;{$ENDIF}
  5371. begin
  5372. Assert(Length(AValue) >= (AIndex+SizeOf(LongInt)));
  5373. {$IFDEF DOTNET}
  5374. Result := System.BitConverter.ToInt32(AValue, AIndex);
  5375. {$ELSE}
  5376. Result := PLongInt(@AValue[AIndex])^;
  5377. {$ENDIF}
  5378. end;
  5379. function BytesToInt64(const AValue: TIdBytes; const AIndex: Integer = 0): Int64;
  5380. {$IFDEF USE_INLINE}inline;{$ENDIF}
  5381. begin
  5382. Assert(Length(AValue) >= (AIndex+SizeOf(Int64)));
  5383. {$IFDEF DOTNET}
  5384. Result := System.BitConverter.ToInt64(AValue, AIndex);
  5385. {$ELSE}
  5386. Result := PInt64(@AValue[AIndex])^;
  5387. {$ENDIF}
  5388. end;
  5389. function BytesToWord(const AValue: TIdBytes; const AIndex: Integer = 0): Word;
  5390. {$IFDEF USE_INLINE}inline;{$ENDIF}
  5391. begin
  5392. Assert(Length(AValue) >= (AIndex+SizeOf(Word)));
  5393. {$IFDEF DOTNET}
  5394. Result := System.BitConverter.ToUInt16(AValue, AIndex);
  5395. {$ELSE}
  5396. Result := PWord(@AValue[AIndex])^;
  5397. {$ENDIF}
  5398. end;
  5399. function BytesToShort(const AValue: TIdBytes; const AIndex: Integer = 0): Short;
  5400. {$IFDEF USE_INLINE}inline;{$ENDIF}
  5401. begin
  5402. Assert(Length(AValue) >= (AIndex+SizeOf(Short)));
  5403. {$IFDEF DOTNET}
  5404. Result := System.BitConverter.ToInt16(AValue, AIndex);
  5405. {$ELSE}
  5406. Result := PSmallInt(@AValue[AIndex])^;
  5407. {$ENDIF}
  5408. end;
  5409. function BytesToIPv4Str(const AValue: TIdBytes; const AIndex: Integer = 0): String;
  5410. {$IFDEF USE_INLINE}inline;{$ENDIF}
  5411. begin
  5412. Assert(Length(AValue) >= (AIndex+4));
  5413. Result := IntToStr(Ord(AValue[AIndex])) + '.' +
  5414. IntToStr(Ord(AValue[AIndex+1])) + '.' +
  5415. IntToStr(Ord(AValue[AIndex+2])) + '.' +
  5416. IntToStr(Ord(AValue[AIndex+3]));
  5417. end;
  5418. procedure BytesToIPv6(const AValue: TIdBytes; var VAddress: TIdIPv6Address; const AIndex: Integer = 0);
  5419. {$IFDEF DOTNET}
  5420. var
  5421. I: Integer;
  5422. {$ELSE}
  5423. {$IFDEF USE_INLINE}inline;{$ENDIF}
  5424. {$ENDIF}
  5425. begin
  5426. Assert(Length(AValue) >= (AIndex+16));
  5427. {$IFDEF DOTNET}
  5428. for i := 0 to 7 do begin
  5429. VAddress[i] := TwoByteToWord(AValue[(i*2)+AIndex], AValue[(i*2)+1+AIndex]);
  5430. end;
  5431. {$ELSE}
  5432. Move(AValue[AIndex], VAddress[0], 16);
  5433. {$ENDIF}
  5434. end;
  5435. function BytesToLongWord(const AValue: TIdBytes; const AIndex: Integer = 0): LongWord;
  5436. {$IFDEF USE_INLINE}inline;{$ENDIF}
  5437. begin
  5438. Assert(Length(AValue) >= (AIndex+SizeOf(LongWord)));
  5439. {$IFDEF DOTNET}
  5440. Result := System.BitConverter.ToUInt32(AValue, AIndex);
  5441. {$ELSE}
  5442. Result := PLongWord(@AValue[AIndex])^;
  5443. {$ENDIF}
  5444. end;
  5445. function BytesToString(const AValue: TIdBytes; AByteEncoding: TIdTextEncoding = nil
  5446. {$IFDEF STRING_IS_ANSI}; ADestEncoding: TIdTextEncoding = nil{$ENDIF}
  5447. ): string; overload;
  5448. {$IFDEF USE_INLINE}inline;{$ENDIF}
  5449. begin
  5450. Result := BytesToString(AValue, 0, -1, AByteEncoding
  5451. {$IFDEF STRING_IS_ANSI}, ADestEncoding{$ENDIF}
  5452. );
  5453. end;
  5454. function BytesToString(const AValue: TIdBytes; const AStartIndex: Integer;
  5455. const ALength: Integer = -1; AByteEncoding: TIdTextEncoding = nil
  5456. {$IFDEF STRING_IS_ANSI}; ADestEncoding: TIdTextEncoding = nil{$ENDIF}
  5457. ): string; overload;
  5458. var
  5459. LLength: Integer;
  5460. {$IFDEF STRING_IS_ANSI}
  5461. LBytes: TIdBytes;
  5462. {$ENDIF}
  5463. begin
  5464. {$IFDEF STRING_IS_ANSI}
  5465. LBytes := nil; // keep the compiler happy
  5466. {$ENDIF}
  5467. LLength := IndyLength(AValue, ALength, AStartIndex);
  5468. if LLength > 0 then begin
  5469. EnsureEncoding(AByteEncoding);
  5470. {$IFDEF STRING_IS_UNICODE}
  5471. Result := AByteEncoding.GetString(AValue, AStartIndex, LLength);
  5472. {$ELSE}
  5473. EnsureEncoding(ADestEncoding);
  5474. LBytes := Copy(AValue, AStartIndex, LLength);
  5475. if AByteEncoding <> ADestEncoding then begin
  5476. LBytes := TIdTextEncoding.Convert(AByteEncoding, ADestEncoding, LBytes);
  5477. end;
  5478. SetString(Result, PAnsiChar(LBytes), Length(LBytes));
  5479. {$ENDIF}
  5480. end else begin
  5481. Result := '';
  5482. end;
  5483. end;
  5484. function BytesToStringRaw(const AValue: TIdBytes): string; overload;
  5485. {$IFDEF USE_INLINE}inline;{$ENDIF}
  5486. begin
  5487. Result := BytesToStringRaw(AValue, 0, -1);
  5488. end;
  5489. function BytesToStringRaw(const AValue: TIdBytes; const AStartIndex: Integer;
  5490. const ALength: Integer = -1): string;
  5491. var
  5492. LLength: Integer;
  5493. begin
  5494. LLength := IndyLength(AValue, ALength, AStartIndex);
  5495. if LLength > 0 then begin
  5496. {$IFDEF STRING_IS_UNICODE}
  5497. Result := Indy8BitEncoding.GetString(AValue, AStartIndex, LLength);
  5498. {$ELSE}
  5499. SetString(Result, PAnsiChar(@AValue[AStartIndex]), LLength);
  5500. {$ENDIF}
  5501. end else begin
  5502. Result := '';
  5503. end;
  5504. end;
  5505. {$IFNDEF DOTNET}
  5506. procedure BytesToRaw(const AValue: TIdBytes; var VBuffer; const ASize: Integer);
  5507. {$IFDEF USE_INLINE}inline;{$ENDIF}
  5508. begin
  5509. Assert(Length(AValue) >= ASize);
  5510. Move(AValue[0], VBuffer, ASize);
  5511. end;
  5512. {$ENDIF}
  5513. function TwoByteToWord(AByte1, AByte2: Byte): Word;
  5514. //Since Replys are returned as Strings, we need a routine to convert two
  5515. // characters which are a 2 byte U Int into a two byte unsigned Integer
  5516. var
  5517. LWord: TIdBytes;
  5518. begin
  5519. SetLength(LWord, 2);
  5520. LWord[0] := AByte1;
  5521. LWord[1] := AByte2;
  5522. Result := BytesToWord(LWord);
  5523. // Result := Word((AByte1 shl 8) and $FF00) or Word(AByte2 and $00FF);
  5524. end;
  5525. function ReadStringFromStream(AStream: TStream; ASize: Integer = -1;
  5526. AByteEncoding: TIdTextEncoding = nil
  5527. {$IFDEF STRING_IS_ANSI}; ADestEncoding: TIdTextEncoding = nil{$ENDIF}
  5528. ): string;
  5529. var
  5530. LBytes: TIdBytes;
  5531. begin
  5532. ASize := TIdStreamHelper.ReadBytes(AStream, LBytes, ASize);
  5533. Result := BytesToString(LBytes, 0, ASize, AByteEncoding
  5534. {$IFDEF STRING_IS_ANSI}, ADestEncoding{$ENDIF}
  5535. );
  5536. end;
  5537. function ReadTIdBytesFromStream(const AStream: TStream; var ABytes: TIdBytes;
  5538. const Count: TIdStreamSize; const AIndex: Integer = 0): TIdStreamSize;
  5539. {$IFDEF USE_INLINE}inline;{$ENDIF}
  5540. begin
  5541. Result := TIdStreamHelper.ReadBytes(AStream, ABytes, Count, AIndex);
  5542. end;
  5543. function ReadCharFromStream(AStream: TStream; var VChar: Char;
  5544. AByteEncoding: TIdTextEncoding = nil
  5545. {$IFDEF STRING_IS_ANSI}; ADestEncoding: TIdTextEncoding = nil{$ENDIF}
  5546. ): Integer;
  5547. var
  5548. StartPos: TIdStreamSize;
  5549. Lb: Byte;
  5550. NumChars, NumBytes: Integer;
  5551. LBytes: TIdBytes;
  5552. {$IFDEF DOTNET}
  5553. LChars: array[0..1] of Char;
  5554. {$ELSE}
  5555. LChars: TIdWideChars;
  5556. {$IFDEF STRING_IS_ANSI}
  5557. LWTmp: WideString;
  5558. LATmp: TIdBytes;
  5559. {$ENDIF}
  5560. {$ENDIF}
  5561. function ReadByte: Byte;
  5562. begin
  5563. if AStream.Read(Result{$IFNDEF DOTNET}, 1{$ENDIF}) <> 1 then begin
  5564. raise EIdException.Create('Unable to read byte'); {do not localize}
  5565. end;
  5566. end;
  5567. begin
  5568. Result := 0;
  5569. {$IFDEF STRING_IS_ANSI}
  5570. LATmp := nil; // keep the compiler happy
  5571. {$ENDIF}
  5572. EnsureEncoding(AByteEncoding);
  5573. StartPos := AStream.Position;
  5574. // don't raise an exception here, backwards compatibility for now
  5575. if AStream.Read(Lb{$IFNDEF DOTNET}, 1{$ENDIF}) <> 1 then begin
  5576. Exit;
  5577. end;
  5578. Result := 1;
  5579. // 2 Chars to handle UTF-16 surrogates
  5580. NumBytes := AByteEncoding.GetMaxByteCount(2);
  5581. SetLength(LBytes, NumBytes);
  5582. {$IFNDEF DOTNET}
  5583. SetLength(LChars, 2);
  5584. {$ENDIF}
  5585. try
  5586. repeat
  5587. LBytes[Result-1] := Lb;
  5588. NumChars := AByteEncoding.GetChars(LBytes, 0, Result, LChars, 0);
  5589. if (NumChars > 0) or (Result = NumBytes) then begin
  5590. Break;
  5591. end;
  5592. Lb := ReadByte;
  5593. Inc(Result);
  5594. until False;
  5595. except
  5596. AStream.Position := StartPos;
  5597. raise;
  5598. end;
  5599. {$IFDEF STRING_IS_UNICODE}
  5600. // RLebeau: if the bytes were decoded into surrogates, the second
  5601. // surrogate is lost here, as it can't be returned unless we cache
  5602. // it somewhere for the the next ReadTIdBytesFromStream() call to
  5603. // retreive. Just raise an error for now. Users will have to
  5604. // update their code to read surrogates differently...
  5605. Assert(NumChars = 1);
  5606. VChar := LChars[0];
  5607. {$ELSE}
  5608. // RLebeau: since we can only return an AnsiChar here, let's convert
  5609. // the decoded characters, surrogates and all, into their Ansi
  5610. // representation. This will have the same problem as above if the
  5611. // conversion results in a multibyte character sequence...
  5612. EnsureEncoding(ADestEncoding, encOSDefault);
  5613. SetString(LWTmp, PWideChar(LChars), NumChars);
  5614. LATmp := ADestEncoding.GetBytes(LWTmp); // convert to Ansi
  5615. Assert(Length(LATmp) = 1);
  5616. VChar := Char(LATmp[0]);
  5617. {$ENDIF}
  5618. end;
  5619. procedure WriteTIdBytesToStream(const AStream: TStream; const ABytes: TIdBytes;
  5620. const ASize: Integer = -1; const AIndex: Integer = 0);
  5621. {$IFDEF USE_INLINE}inline;{$ENDIF}
  5622. begin
  5623. TIdStreamHelper.Write(AStream, ABytes, ASize, AIndex);
  5624. end;
  5625. procedure WriteStringToStream(AStream: TStream; const AStr: string;
  5626. ADestEncoding: TIdTextEncoding
  5627. {$IFDEF STRING_IS_ANSI}; ASrcEncoding: TIdTextEncoding = nil{$ENDIF}
  5628. );
  5629. {$IFDEF USE_INLINE}inline;{$ENDIF}
  5630. begin
  5631. WriteStringToStream(AStream, AStr, -1, 1, ADestEncoding
  5632. {$IFDEF STRING_IS_ANSI}, ASrcEncoding{$ENDIF}
  5633. );
  5634. end;
  5635. procedure WriteStringToStream(AStream: TStream; const AStr: string;
  5636. const ALength: Integer = -1; const AIndex: Integer = 1;
  5637. ADestEncoding: TIdTextEncoding = nil
  5638. {$IFDEF STRING_IS_ANSI}; ASrcEncoding: TIdTextEncoding = nil{$ENDIF}
  5639. );
  5640. {$IFDEF USE_INLINE}inline;{$ENDIF}
  5641. var
  5642. LLength: Integer;
  5643. LBytes: TIdBytes;
  5644. begin
  5645. LBytes := nil;
  5646. LLength := IndyLength(AStr, ALength, AIndex);
  5647. if LLength > 0 then
  5648. begin
  5649. LBytes := ToBytes(AStr, LLength, AIndex, ADestEncoding
  5650. {$IFDEF STRING_IS_ANSI}, ASrcEncoding{$ENDIF}
  5651. );
  5652. TIdStreamHelper.Write(AStream, LBytes);
  5653. end;
  5654. end;
  5655. {$IFDEF DOTNET}
  5656. function TIdBaseStream.Read(var VBuffer: array of Byte; AOffset, ACount: Longint): Longint;
  5657. var
  5658. LBytes: TIdBytes;
  5659. begin
  5660. // this is a silly work around really, but array of Byte and TIdByte aren't
  5661. // interchangable in a var parameter, though really they *should be*
  5662. SetLength(LBytes, ACount - AOffset);
  5663. Result := IdRead(LBytes, 0, ACount - AOffset);
  5664. CopyTIdByteArray(LBytes, 0, VBuffer, AOffset, Result);
  5665. end;
  5666. function TIdBaseStream.Write(const ABuffer: array of Byte; AOffset, ACount: Longint): Longint;
  5667. begin
  5668. Result := IdWrite(ABuffer, AOffset, ACount);
  5669. end;
  5670. function TIdBaseStream.Seek(const AOffset: Int64; AOrigin: TSeekOrigin): Int64;
  5671. begin
  5672. Result := IdSeek(AOffset, AOrigin);
  5673. end;
  5674. procedure TIdBaseStream.SetSize(ASize: Int64);
  5675. begin
  5676. IdSetSize(ASize);
  5677. end;
  5678. {$ELSE}
  5679. {$IFDEF STREAM_SIZE_64}
  5680. procedure TIdBaseStream.SetSize(const NewSize: Int64);
  5681. begin
  5682. IdSetSize(NewSize);
  5683. end;
  5684. {$ELSE}
  5685. procedure TIdBaseStream.SetSize(ASize: Integer);
  5686. begin
  5687. IdSetSize(ASize);
  5688. end;
  5689. {$ENDIF}
  5690. function TIdBaseStream.Read(var Buffer; Count: Longint): Longint;
  5691. var
  5692. LBytes: TIdBytes;
  5693. begin
  5694. SetLength(LBytes, Count);
  5695. Result := IdRead(LBytes, 0, Count);
  5696. if Result > 0 then begin
  5697. Move(LBytes[0], Buffer, Result);
  5698. end;
  5699. end;
  5700. function TIdBaseStream.Write(const Buffer; Count: Longint): Longint;
  5701. begin
  5702. if Count > 0 then begin
  5703. Result := IdWrite(RawToBytes(Buffer, Count), 0, Count);
  5704. end else begin
  5705. Result := 0;
  5706. end;
  5707. end;
  5708. {$IFDEF STREAM_SIZE_64}
  5709. function TIdBaseStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64;
  5710. begin
  5711. Result := IdSeek(Offset, Origin);
  5712. end;
  5713. {$ELSE}
  5714. function TIdBaseStream.Seek(Offset: Longint; Origin: Word): Longint;
  5715. var
  5716. LSeek : TSeekOrigin;
  5717. begin
  5718. case Origin of
  5719. soFromBeginning : LSeek := soBeginning;
  5720. soFromCurrent : LSeek := soCurrent;
  5721. soFromEnd : LSeek := soEnd;
  5722. else
  5723. Result := 0;
  5724. Exit;
  5725. end;
  5726. Result := IdSeek(Offset, LSeek) and $FFFFFFFF;
  5727. end;
  5728. {$ENDIF}
  5729. {$ENDIF}
  5730. function TIdEventStream.IdRead(var VBuffer: TIdBytes; AOffset, ACount: Longint): Longint;
  5731. begin
  5732. Result := 0;
  5733. if Assigned(FOnRead) then begin
  5734. FOnRead(VBuffer, AOffset, ACount, Result);
  5735. end;
  5736. end;
  5737. function TIdEventStream.IdWrite(const ABuffer: TIdBytes; AOffset, ACount: Longint): Longint;
  5738. begin
  5739. if Assigned(FOnWrite) then begin
  5740. Result := 0;
  5741. FOnWrite(ABuffer, AOffset, ACount, Result);
  5742. end else begin
  5743. Result := ACount;
  5744. end;
  5745. end;
  5746. function TIdEventStream.IdSeek(const AOffset: Int64; AOrigin: TSeekOrigin): Int64;
  5747. begin
  5748. Result := 0;
  5749. if Assigned(FOnSeek) then begin
  5750. FOnSeek(AOffset, AOrigin, Result);
  5751. end;
  5752. end;
  5753. procedure TIdEventStream.IdSetSize(ASize: Int64);
  5754. begin
  5755. if Assigned(FOnSetSize) then begin
  5756. FOnSetSize(ASize);
  5757. end;
  5758. end;
  5759. {$IFNDEF DOTNET}
  5760. constructor TIdMemoryBufferStream.Create(APtr: Pointer; ASize: TIdNativeInt);
  5761. begin
  5762. inherited Create;
  5763. SetPointer(APtr, ASize);
  5764. end;
  5765. function TIdMemoryBufferStream.Write(const Buffer; Count: Longint): Longint;
  5766. var
  5767. LNumToCopy: Longint;
  5768. begin
  5769. Result := 0;
  5770. if (Position >= 0) and (Size > 0) and (Count > 0) then
  5771. begin
  5772. LNumToCopy := IndyMin(Size - Position, Count);
  5773. if LNumToCopy > 0 then
  5774. begin
  5775. System.Move(Buffer, Pointer(PtrInt(Memory) + Position)^, Count);
  5776. TIdStreamHelper.Seek(Self, LNumToCopy, soCurrent);
  5777. Result := LNumToCopy;
  5778. end;
  5779. end;
  5780. end;
  5781. {$ENDIF}
  5782. procedure AppendBytes(var VBytes: TIdBytes; const AToAdd: TIdBytes; const AIndex: Integer = 0; const ALength: Integer = -1);
  5783. var
  5784. LOldLen, LAddLen: Integer;
  5785. begin
  5786. LAddLen := IndyLength(AToAdd, ALength, AIndex);
  5787. if LAddLen > 0 then begin
  5788. LOldLen := Length(VBytes);
  5789. SetLength(VBytes, LOldLen + LAddLen);
  5790. CopyTIdBytes(AToAdd, AIndex, VBytes, LOldLen, LAddLen);
  5791. end;
  5792. end;
  5793. procedure AppendByte(var VBytes: TIdBytes; const AByte: Byte);
  5794. var
  5795. LOldLen: Integer;
  5796. begin
  5797. LOldLen := Length(VBytes);
  5798. SetLength(VBytes, LOldLen + 1);
  5799. VBytes[LOldLen] := AByte;
  5800. end;
  5801. procedure AppendString(var VBytes: TIdBytes; const AStr: String; const ALength: Integer = -1;
  5802. ADestEncoding: TIdTextEncoding = nil
  5803. {$IFDEF STRING_IS_ANSI}; ASrcEncoding: TIdTextEncoding = nil{$ENDIF}
  5804. );
  5805. var
  5806. LBytes: TIdBytes;
  5807. LLength, LOldLen: Integer;
  5808. begin
  5809. LBytes := nil; // keep the compiler happy
  5810. LLength := IndyLength(AStr, ALength);
  5811. if LLength > 0 then begin
  5812. LBytes := ToBytes(AStr, LLength, 1, ADestEncoding
  5813. {$IFDEF STRING_IS_ANSI}, ASrcEncoding{$ENDIF}
  5814. );
  5815. LOldLen := Length(VBytes);
  5816. LLength := Length(LBytes);
  5817. SetLength(VBytes, LOldLen + LLength);
  5818. CopyTIdBytes(LBytes, 0, VBytes, LOldLen, LLength);
  5819. end;
  5820. end;
  5821. procedure ExpandBytes(var VBytes: TIdBytes; const AIndex: Integer; const ACount: Integer; const AFillByte: Byte = 0);
  5822. var
  5823. I: Integer;
  5824. begin
  5825. if ACount > 0 then begin
  5826. // if AIndex is at the end of the buffer then the operation is appending bytes
  5827. if AIndex <> Length(VBytes) then begin
  5828. //if these asserts fail, then it indicates an attempted buffer overrun.
  5829. Assert(AIndex >= 0);
  5830. Assert(AIndex < Length(VBytes));
  5831. end;
  5832. SetLength(VBytes, Length(VBytes) + ACount);
  5833. // move any existing bytes at the index to the end of the buffer
  5834. for I := Length(VBytes)-1 downto AIndex+ACount do begin
  5835. VBytes[I] := VBytes[I-ACount];
  5836. end;
  5837. // fill in the new space with the fill byte
  5838. for I := AIndex to AIndex+ACount-1 do begin
  5839. VBytes[I] := AFillByte;
  5840. end;
  5841. end;
  5842. end;
  5843. procedure InsertBytes(var VBytes: TIdBytes; const ADestIndex: Integer;
  5844. const ASource: TIdBytes; const ASourceIndex: Integer = 0);
  5845. var
  5846. LAddLen: Integer;
  5847. begin
  5848. LAddLen := IndyLength(ASource, -1, ASourceIndex);
  5849. if LAddLen > 0 then begin
  5850. ExpandBytes(VBytes, ADestIndex, LAddLen);
  5851. CopyTIdBytes(ASource, ASourceIndex, VBytes, ADestIndex, LAddLen);
  5852. end;
  5853. end;
  5854. procedure InsertByte(var VBytes: TIdBytes; const AByte: Byte; const AIndex: Integer);
  5855. {$IFDEF USE_INLINE}inline;{$ENDIF}
  5856. begin
  5857. ExpandBytes(VBytes, AIndex, 1);
  5858. VBytes[AIndex] := AByte;
  5859. end;
  5860. procedure RemoveBytes(var VBytes: TIdBytes; const ACount: Integer; const AIndex: Integer = 0);
  5861. var
  5862. I: Integer;
  5863. LActual: Integer;
  5864. begin
  5865. Assert(AIndex >= 0);
  5866. LActual := IndyMin(Length(VBytes)-AIndex, ACount);
  5867. if LActual > 0 then begin
  5868. if (AIndex + LActual) < Length(VBytes) then begin
  5869. // RLebeau: TODO - use Move() here instead?
  5870. for I := AIndex to Length(VBytes)-LActual-1 do begin
  5871. VBytes[I] := VBytes[I+LActual];
  5872. end;
  5873. end;
  5874. SetLength(VBytes, Length(VBytes)-LActual);
  5875. end;
  5876. end;
  5877. procedure IdDelete(var s: string; AOffset, ACount: Integer);
  5878. {$IFDEF USE_INLINE}inline;{$ENDIF}
  5879. begin
  5880. Delete(s, AOffset, ACount);
  5881. end;
  5882. procedure IdInsert(const Source: string; var S: string; Index: Integer);
  5883. {$IFDEF USE_INLINE}inline;{$ENDIF}
  5884. begin
  5885. Insert(Source, S, Index);
  5886. end;
  5887. function TextIsSame(const A1, A2: string): Boolean;
  5888. {$IFDEF USE_INLINE}inline;{$ENDIF}
  5889. begin
  5890. {$IFDEF DOTNET}
  5891. Result := System.String.Compare(A1, A2, True) = 0;
  5892. {$ELSE}
  5893. Result := AnsiCompareText(A1, A2) = 0;
  5894. {$ENDIF}
  5895. end;
  5896. function TextStartsWith(const S, SubS: string): Boolean;
  5897. var
  5898. LLen: Integer;
  5899. {$IFDEF WINDOWS}
  5900. {$IFDEF UNICODE_BUT_STRING_IS_ANSI}
  5901. LS, LSub: WideString;
  5902. P1, P2: PWideChar;
  5903. {$ELSE}
  5904. P1, P2: PChar;
  5905. {$ENDIF}
  5906. {$ENDIF}
  5907. begin
  5908. LLen := Length(SubS);
  5909. Result := LLen <= Length(S);
  5910. if Result then
  5911. begin
  5912. {$IFDEF DOTNET}
  5913. Result := System.String.Compare(S, 0, SubS, 0, LLen, True) = 0;
  5914. {$ELSE}
  5915. {$IFDEF WINDOWS}
  5916. {$IFDEF UNICODE_BUT_STRING_IS_ANSI}
  5917. // convert to Unicode
  5918. LS := S;
  5919. LSub := SubS;
  5920. P1 := PWideChar(LS);
  5921. P2 := PWideChar(LSub);
  5922. {$ELSE}
  5923. P1 := PChar(S);
  5924. P2 := PChar(SubS);
  5925. {$ENDIF}
  5926. Result := CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, P1, LLen, P2, LLen) = 2;
  5927. {$ELSE}
  5928. Result := AnsiCompareText(Copy(S, 1, LLen), SubS) = 0;
  5929. {$ENDIF}
  5930. {$ENDIF}
  5931. end;
  5932. end;
  5933. function TextEndsWith(const S, SubS: string): Boolean;
  5934. var
  5935. LLen: Integer;
  5936. {$IFDEF WINDOWS}
  5937. {$IFDEF UNICODE_BUT_STRING_IS_ANSI}
  5938. LS, LSubS: WideString;
  5939. P1, P2: PWideChar;
  5940. {$ELSE}
  5941. P1, P2: PChar;
  5942. {$ENDIF}
  5943. {$ENDIF}
  5944. begin
  5945. LLen := Length(SubS);
  5946. Result := LLen <= Length(S);
  5947. if Result then
  5948. begin
  5949. {$IFDEF DOTNET}
  5950. Result := System.String.Compare(S, Length(S)-LLen, SubS, 0, LLen, True) = 0;
  5951. {$ELSE}
  5952. {$IFDEF WINDOWS}
  5953. {$IFDEF UNICODE_BUT_STRING_IS_ANSI}
  5954. // convert to Unicode
  5955. LS := S;
  5956. LSubS := SubS;
  5957. P1 := PWideChar(LS);
  5958. P2 := PWideChar(LSubS);
  5959. {$ELSE}
  5960. P1 := PChar(S);
  5961. P2 := PChar(SubS);
  5962. {$ENDIF}
  5963. Inc(P1, Length(S)-LLen);
  5964. Result := CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, P1, LLen, P2, LLen) = 2;
  5965. {$ELSE}
  5966. Result := AnsiCompareText(Copy(S, Length(S)-LLen+1, LLen), SubS) = 0;
  5967. {$ENDIF}
  5968. {$ENDIF}
  5969. end;
  5970. end;
  5971. function IndyLowerCase(const A1: string): string;
  5972. {$IFDEF USE_INLINE}inline;{$ENDIF}
  5973. begin
  5974. {$IFDEF DOTNET}
  5975. Result := A1.ToLower;
  5976. {$ELSE}
  5977. Result := AnsiLowerCase(A1);
  5978. {$ENDIF}
  5979. end;
  5980. function IndyUpperCase(const A1: string): string;
  5981. {$IFDEF USE_INLINE}inline;{$ENDIF}
  5982. begin
  5983. {$IFDEF DOTNET}
  5984. Result := A1.ToUpper;
  5985. {$ELSE}
  5986. Result := AnsiUpperCase(A1);
  5987. {$ENDIF}
  5988. end;
  5989. function IndyCompareStr(const A1, A2: string): Integer;
  5990. {$IFDEF USE_INLINE}inline;{$ENDIF}
  5991. begin
  5992. {$IFDEF DOTNET}
  5993. Result := CompareStr(A1, A2);
  5994. {$ELSE}
  5995. Result := AnsiCompareStr(A1, A2);
  5996. {$ENDIF}
  5997. end;
  5998. function CharPosInSet(const AString: string; const ACharPos: Integer; const ASet: String): Integer;
  5999. {$IFDEF USE_INLINE}inline;{$ENDIF}
  6000. {$IFNDEF DOTNET}
  6001. var
  6002. LChar: Char;
  6003. I: Integer;
  6004. {$ENDIF}
  6005. begin
  6006. Result := 0;
  6007. if ACharPos < 1 then begin
  6008. EIdException.Toss('Invalid ACharPos');{ do not localize }
  6009. end;
  6010. if ACharPos <= Length(AString) then begin
  6011. {$IFDEF DOTNET}
  6012. Result := ASet.IndexOf(AString[ACharPos]) + 1;
  6013. {$ELSE}
  6014. // RLebeau 5/8/08: Calling Pos() with a Char as input creates a temporary
  6015. // String. Normally this is fine, but profiling reveils this to be a big
  6016. // bottleneck for code that makes a lot of calls to CharIsInSet(), so need
  6017. // to scan through ASet looking for the character without a conversion...
  6018. //
  6019. // Result := IndyPos(AString[ACharPos], ASet);
  6020. //
  6021. LChar := AString[ACharPos];
  6022. for I := 1 to Length(ASet) do begin
  6023. if ASet[I] = LChar then begin
  6024. Result := I;
  6025. Exit;
  6026. end;
  6027. end;
  6028. {$ENDIF}
  6029. end;
  6030. end;
  6031. function CharIsInSet(const AString: string; const ACharPos: Integer; const ASet: String): Boolean;
  6032. {$IFDEF USE_INLINE}inline;{$ENDIF}
  6033. begin
  6034. Result := CharPosInSet(AString, ACharPos, ASet) > 0;
  6035. end;
  6036. function CharIsInEOL(const AString: string; const ACharPos: Integer): Boolean;
  6037. {$IFDEF USE_INLINE}inline;{$ENDIF}
  6038. begin
  6039. Result := CharIsInSet(AString, ACharPos, EOL);
  6040. end;
  6041. function CharEquals(const AString: string; const ACharPos: Integer; const AValue: Char): Boolean;
  6042. {$IFDEF USE_INLINE}inline;{$ENDIF}
  6043. begin
  6044. if ACharPos < 1 then begin
  6045. EIdException.Toss('Invalid ACharPos');{ do not localize }
  6046. end;
  6047. Result := ACharPos <= Length(AString);
  6048. if Result then begin
  6049. Result := AString[ACharPos] = AValue;
  6050. end;
  6051. end;
  6052. function ByteIndex(const AByte: Byte; const ABytes: TIdBytes; const AStartIndex: Integer = 0): Integer;
  6053. var
  6054. I: Integer;
  6055. begin
  6056. Result := -1;
  6057. for I := AStartIndex to Length(ABytes)-1 do begin
  6058. if ABytes[I] = AByte then begin
  6059. Result := I;
  6060. Exit;
  6061. end;
  6062. end;
  6063. end;
  6064. function ByteIdxInSet(const ABytes: TIdBytes; const AIndex: Integer; const ASet: TIdBytes): Integer;
  6065. {$IFDEF USE_INLINE}inline;{$ENDIF}
  6066. begin
  6067. if AIndex < 0 then begin
  6068. EIdException.Toss('Invalid AIndex'); {do not localize}
  6069. end;
  6070. if AIndex < Length(ABytes) then begin
  6071. Result := ByteIndex(ABytes[AIndex], ASet);
  6072. end else begin
  6073. Result := -1;
  6074. end;
  6075. end;
  6076. function ByteIsInSet(const ABytes: TIdBytes; const AIndex: Integer; const ASet: TIdBytes): Boolean;
  6077. {$IFDEF USE_INLINE}inline;{$ENDIF}
  6078. begin
  6079. Result := ByteIdxInSet(ABytes, AIndex, ASet) > -1;
  6080. end;
  6081. function ByteIsInEOL(const ABytes: TIdBytes; const AIndex: Integer): Boolean;
  6082. var
  6083. LSet: TIdBytes;
  6084. begin
  6085. SetLength(LSet, 2);
  6086. LSet[0] := 13;
  6087. LSet[1] := 10;
  6088. Result := ByteIsInSet(ABytes, AIndex, LSet);
  6089. end;
  6090. function ReadLnFromStream(AStream: TStream; AMaxLineLength: Integer = -1;
  6091. AExceptionIfEOF: Boolean = False; AByteEncoding: TIdTextEncoding = nil
  6092. {$IFDEF STRING_IS_ANSI}; ADestEncoding: TIdTextEncoding = nil{$ENDIF}
  6093. ): string; overload;
  6094. begin
  6095. if (not ReadLnFromStream(AStream, Result, AMaxLineLength, AByteEncoding
  6096. {$IFDEF STRING_IS_ANSI}, ADestEncoding{$ENDIF}
  6097. )) and AExceptionIfEOF then
  6098. begin
  6099. EIdEndOfStream.Toss(IndyFormat(RSEndOfStream, ['', AStream.Position]));
  6100. end;
  6101. end;
  6102. //TODO: Continue to optimize this function. Its performance severely impacts the coders
  6103. function ReadLnFromStream(AStream: TStream; var VLine: String; AMaxLineLength: Integer = -1;
  6104. AByteEncoding: TIdTextEncoding = nil
  6105. {$IFDEF STRING_IS_ANSI}; ADestEncoding: TIdTextEncoding = nil{$ENDIF}
  6106. ): Boolean; overload;
  6107. const
  6108. LBUFMAXSIZE = 2048;
  6109. var
  6110. LStringLen, LResultLen: LongInt;
  6111. LBuf: TIdBytes;
  6112. LLine: TIdBytes;
  6113. // LBuf: packed array [0..LBUFMAXSIZE] of Char;
  6114. LBufSize, LStrmPos, LStrmSize: TIdStreamSize; //LBytesToRead = stream size - Position
  6115. LCrEncountered: Boolean;
  6116. function FindEOL(const ABuf: TIdBytes; var VLineBufSize: TIdStreamSize; var VCrEncountered: Boolean): TIdStreamSize;
  6117. var
  6118. i: Integer;
  6119. begin
  6120. Result := VLineBufSize; //EOL not found => use all
  6121. i := 0;
  6122. while i < VLineBufSize do begin
  6123. case ABuf[i] of
  6124. Ord(LF): begin
  6125. Result := i; {string size}
  6126. VCrEncountered := True;
  6127. VLineBufSize := i+1;
  6128. Break;
  6129. end;
  6130. Ord(CR): begin
  6131. Result := i; {string size}
  6132. VCrEncountered := True;
  6133. Inc(i); //crLF?
  6134. if (i < VLineBufSize) and (ABuf[i] = Ord(LF)) then begin
  6135. VLineBufSize := i+1;
  6136. end else begin
  6137. VLineBufSize := i;
  6138. end;
  6139. Break;
  6140. end;
  6141. end;
  6142. Inc(i);
  6143. end;
  6144. end;
  6145. begin
  6146. Assert(AStream<>nil);
  6147. VLine := '';
  6148. SetLength(LLine, 0);
  6149. if AMaxLineLength < 0 then begin
  6150. AMaxLineLength := MaxInt;
  6151. end;
  6152. { we store the stream size for the whole routine to prevent
  6153. so do not incur a performance penalty with TStream.Size. It has
  6154. to use something such as Seek each time the size is obtained}
  6155. {4 seek vs 3 seek}
  6156. LStrmPos := AStream.Position;
  6157. LStrmSize := AStream.Size;
  6158. if LStrmPos >= LStrmSize then begin
  6159. Result := False;
  6160. Exit;
  6161. end;
  6162. SetLength(LBuf, LBUFMAXSIZE);
  6163. LCrEncountered := False;
  6164. repeat
  6165. LBufSize := IndyMin(LStrmSize - LStrmPos, LBUFMAXSIZE);
  6166. LBufSize := ReadTIdBytesFromStream(AStream, LBuf, LBufSize);
  6167. LStringLen := FindEOL(LBuf, LBufSize, LCrEncountered);
  6168. Inc(LStrmPos, LBufSize);
  6169. LResultLen := Length(VLine);
  6170. if (LResultLen + LStringLen) > AMaxLineLength then begin
  6171. LStringLen := AMaxLineLength - LResultLen;
  6172. LCrEncountered := True;
  6173. Dec(LStrmPos, LBufSize);
  6174. Inc(LStrmPos, LStringLen);
  6175. end;
  6176. if LStringLen > 0 then begin
  6177. LBufSize := Length(LLine);
  6178. SetLength(LLine, LBufSize+LStringLen);
  6179. CopyTIdBytes(LBuf, 0, LLine, LBufSize, LStringLen);
  6180. end;
  6181. until (LStrmPos >= LStrmSize) or LCrEncountered;
  6182. AStream.Position := LStrmPos;
  6183. VLine := BytesToString(LLine, 0, -1, AByteEncoding
  6184. {$IFDEF STRING_IS_ANSI}, ADestEncoding{$ENDIF}
  6185. );
  6186. Result := True;
  6187. end;
  6188. {$IFNDEF DOTNET}
  6189. {$IFDEF REGISTER_EXPECTED_MEMORY_LEAK}
  6190. function IndyRegisterExpectedMemoryLeak(AAddress: Pointer): Boolean;
  6191. {$IFDEF USE_INLINE}inline;{$ENDIF}
  6192. begin
  6193. {$IFDEF USE_FASTMM4}
  6194. // RLebeau 4/9/2009: the user can override the RTL's version of FastMM
  6195. // (2006+ only) with the full version of FastMM in order to enable
  6196. // advanced debugging features, so check for that first...
  6197. Result := FastMM4.RegisterExpectedMemoryLeak(AAddress);
  6198. {$ELSE}
  6199. {$IFDEF HAS_System_RegisterExpectedMemoryLeak}
  6200. // RLebeau 4/21/08: not quite sure what the difference is between the
  6201. // SysRegisterExpectedMemoryLeak() and RegisterExpectedMemoryLeak()
  6202. // functions in the System unit, but calling RegisterExpectedMemoryLeak()
  6203. // is causing stack overflows when FastMM is not active, so call
  6204. // SysRegisterExpectedMemoryLeak() instead...
  6205. // RLebeau 7/4/09: According to Pierre Le Riche, developer of FastMM:
  6206. //
  6207. // "SysRegisterExpectedMemoryLeak() is the leak registration routine for
  6208. // the built-in memory manager. FastMM.RegisterExpectedMemoryLeak is the
  6209. // leak registration code for FastMM. Both of these are thus hardwired to
  6210. // a specific memory manager. In order to register a leak for the
  6211. // *currently installed* memory manager, which is what you typically want
  6212. // to do, you have to call System.RegisterExpectedMemoryLeak().
  6213. // System.RegisterExpectedMemoryLeak() redirects to the leak registration
  6214. // code of the installed memory manager."
  6215. //Result := System.SysRegisterExpectedMemoryLeak(AAddress);
  6216. Result := System.RegisterExpectedMemoryLeak(AAddress);
  6217. {$ELSE}
  6218. Result := False;
  6219. {$ENDIF}
  6220. {$ENDIF}
  6221. end;
  6222. {$ENDIF}
  6223. {$ENDIF}
  6224. function InternalIndyIndexOf(AStrings: TStrings; const AStr: string;
  6225. const ACaseSensitive: Boolean = False): Integer;
  6226. {$IFDEF USE_INLINE}inline;{$ENDIF}
  6227. var
  6228. I: Integer;
  6229. begin
  6230. Result := -1;
  6231. for I := 0 to AStrings.Count - 1 do begin
  6232. if ACaseSensitive then begin
  6233. if AStrings[I] = AStr then begin
  6234. Result := I;
  6235. Exit;
  6236. end;
  6237. end else begin
  6238. if TextIsSame(AStrings[I], AStr) then begin
  6239. Result := I;
  6240. Exit;
  6241. end;
  6242. end;
  6243. end;
  6244. end;
  6245. function IndyIndexOf(AStrings: TStrings; const AStr: string;
  6246. const ACaseSensitive: Boolean = False): Integer;
  6247. begin
  6248. {$IFDEF HAS_TStringList_CaseSensitive}
  6249. if AStrings is TStringList then begin
  6250. Result := IndyIndexOf(TStringList(AStrings), AStr, ACaseSensitive);
  6251. Exit;
  6252. end;
  6253. {$ENDIF}
  6254. Result := InternalIndyIndexOf(AStrings, AStr, ACaseSensitive);
  6255. end;
  6256. {$IFDEF HAS_TStringList_CaseSensitive}
  6257. function IndyIndexOf(AStrings: TStringList; const AStr: string;
  6258. const ACaseSensitive: Boolean = False): Integer;
  6259. begin
  6260. if AStrings.CaseSensitive = ACaseSensitive then begin
  6261. Result := AStrings.IndexOf(AStr);
  6262. end else begin
  6263. Result := InternalIndyIndexOf(AStrings, AStr, ACaseSensitive);
  6264. end;
  6265. end;
  6266. {$ENDIF}
  6267. function InternalIndyIndexOfName(AStrings: TStrings; const AStr: string;
  6268. const ACaseSensitive: Boolean = False): Integer;
  6269. {$IFDEF USE_INLINE}inline;{$ENDIF}
  6270. var
  6271. I: Integer;
  6272. begin
  6273. Result := -1;
  6274. for I := 0 to AStrings.Count - 1 do begin
  6275. if ACaseSensitive then begin
  6276. if AStrings.Names[I] = AStr then begin
  6277. Result := I;
  6278. Exit;
  6279. end;
  6280. end else begin
  6281. if TextIsSame(AStrings.Names[I], AStr) then begin
  6282. Result := I;
  6283. Exit;
  6284. end;
  6285. end;
  6286. end;
  6287. end;
  6288. function IndyIndexOfName(AStrings: TStrings; const AStr: string;
  6289. const ACaseSensitive: Boolean = False): Integer;
  6290. begin
  6291. {$IFDEF HAS_TStringList_CaseSensitive}
  6292. if AStrings is TStringList then begin
  6293. Result := IndyIndexOfName(TStringList(AStrings), AStr, ACaseSensitive);
  6294. Exit;
  6295. end;
  6296. {$ENDIF}
  6297. Result := InternalIndyIndexOfName(AStrings, AStr, ACaseSensitive);
  6298. end;
  6299. {$IFDEF HAS_TStringList_CaseSensitive}
  6300. function IndyIndexOfName(AStrings: TStringList; const AStr: string;
  6301. const ACaseSensitive: Boolean = False): Integer;
  6302. begin
  6303. if AStrings.CaseSensitive = ACaseSensitive then begin
  6304. Result := AStrings.IndexOfName(AStr);
  6305. end else begin
  6306. Result := IndyIndexOfName(TStrings(AStrings), AStr, ACaseSensitive);
  6307. end;
  6308. end;
  6309. {$ENDIF}
  6310. initialization
  6311. // AnsiPos does not handle strings with #0 and is also very slow compared to Pos
  6312. {$IFDEF DOTNET}
  6313. IndyPos := SBPos;
  6314. {$ELSE}
  6315. if LeadBytes = [] then begin
  6316. IndyPos := SBPos;
  6317. end else begin
  6318. IndyPos := InternalAnsiPos;
  6319. end;
  6320. {$ENDIF}
  6321. {$IFDEF DYNAMICLOAD_InterlockedCompareExchange}
  6322. InterlockedCompareExchange := Stub_InterlockedCompareExchange;
  6323. {$ENDIF}
  6324. {$IFNDEF DOTNET}
  6325. finalization
  6326. FreeAndNil(GIdPorts);
  6327. FreeAndNil(GId8BitEncoding);
  6328. FreeAndNil(GIdASCIIEncoding);
  6329. FreeAndNil(GIdUTF8Encoding);
  6330. {$IFNDEF TIdTextEncoding_IS_NATIVE}
  6331. TIdTextEncoding.FreeEncodings;
  6332. {$ENDIF}
  6333. {$ENDIF}
  6334. end.