synautil.pas 57 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161
  1. {==============================================================================|
  2. | Project : Ararat Synapse | 004.015.007 |
  3. |==============================================================================|
  4. | Content: support procedures and functions |
  5. |==============================================================================|
  6. | Copyright (c)1999-2017, Lukas Gebauer |
  7. | All rights reserved. |
  8. | |
  9. | Redistribution and use in source and binary forms, with or without |
  10. | modification, are permitted provided that the following conditions are met: |
  11. | |
  12. | Redistributions of source code must retain the above copyright notice, this |
  13. | list of conditions and the following disclaimer. |
  14. | |
  15. | Redistributions in binary form must reproduce the above copyright notice, |
  16. | this list of conditions and the following disclaimer in the documentation |
  17. | and/or other materials provided with the distribution. |
  18. | |
  19. | Neither the name of Lukas Gebauer nor the names of its contributors may |
  20. | be used to endorse or promote products derived from this software without |
  21. | specific prior written permission. |
  22. | |
  23. | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
  24. | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
  25. | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
  26. | ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR |
  27. | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
  28. | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
  29. | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
  30. | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
  31. | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
  32. | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH |
  33. | DAMAGE. |
  34. |==============================================================================|
  35. | The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).|
  36. | Portions created by Lukas Gebauer are Copyright (c) 1999-2017. |
  37. | Portions created by Hernan Sanchez are Copyright (c) 2000. |
  38. | Portions created by Petr Fejfar are Copyright (c)2011-2012. |
  39. | All Rights Reserved. |
  40. |==============================================================================|
  41. | Contributor(s): |
  42. | Hernan Sanchez ([email protected]) |
  43. | Tomas Hajny (OS2 support) |
  44. | Radek Cervinka (POSIX support) |
  45. |==============================================================================|
  46. | History: see HISTORY.HTM from distribution package |
  47. | (Found at URL: http://www.ararat.cz/synapse/) |
  48. |==============================================================================}
  49. {:@abstract(Support procedures and functions)}
  50. {$I jedi.inc} // load common compiler defines
  51. {$Q-}
  52. {$R-}
  53. {$H+}
  54. {$IFDEF UNICODE}
  55. {$WARN IMPLICIT_STRING_CAST OFF}
  56. {$WARN IMPLICIT_STRING_CAST_LOSS OFF}
  57. {$WARN SUSPICIOUS_TYPECAST OFF}
  58. {$WARN SYMBOL_DEPRECATED OFF}
  59. {$ENDIF}
  60. {$IFDEF NEXTGEN}
  61. {$ZEROBASEDSTRINGS OFF}
  62. {$ENDIF}
  63. unit synautil;
  64. interface
  65. uses
  66. {$IFDEF MSWINDOWS}
  67. Windows,
  68. {$ELSE MSWINDOWS}
  69. {$IFDEF ULTIBO}
  70. Ultibo,
  71. {$ELSE}
  72. {$IFDEF FPC}
  73. {$IFDEF OS2}
  74. Dos, TZUtil,
  75. {$ELSE OS2}
  76. UnixUtil, Unix, BaseUnix,
  77. {$ENDIF OS2}
  78. {$ELSE FPC}
  79. {$IFDEF POSIX}
  80. Posix.Base, Posix.Time, Posix.SysTypes, Posix.SysTime, Posix.Stdio,
  81. Posix.Unistd,
  82. {$ELSE}
  83. Libc,
  84. {$ENDIF}
  85. {$ENDIF}
  86. {$ENDIF}
  87. {$ENDIF}
  88. {$IFDEF CIL}
  89. System.IO,
  90. {$ENDIF}
  91. Math, SysUtils, Classes, SynaFpc, synabyte;
  92. {$IFDEF VER100}
  93. type
  94. int64 = integer;
  95. {$ENDIF}
  96. {$IFDEF POSIX}
  97. type
  98. TTimeVal = Posix.SysTime.timeval;
  99. Ttimezone = record
  100. tz_minuteswest: Integer ; // minutes west of Greenwich
  101. tz_dsttime: integer ; // type of DST correction
  102. end;
  103. PTimeZone = ^Ttimezone;
  104. {$ENDIF}
  105. {:Return your timezone bias from UTC time in minutes.}
  106. function TimeZoneBias: integer;
  107. {:Return your timezone bias from UTC time in string representation like "+0200".}
  108. function TimeZone: string;
  109. {:Returns current time in format defined in RFC-822. Useful for SMTP messages,
  110. but other protocols use this time format as well. Results contains the timezone
  111. specification. Four digit year is used to break any Y2K concerns. (Example
  112. 'Fri, 15 Oct 1999 21:14:56 +0200')}
  113. function Rfc822DateTime(t: TDateTime): string;
  114. {:Returns date and time in format defined in C compilers in format "mmm dd hh:nn:ss"}
  115. function CDateTime(t: TDateTime): string;
  116. {:Returns date and time in format defined in format 'yymmdd hhnnss'}
  117. function SimpleDateTime(t: TDateTime): string;
  118. {:Returns date and time in format defined in ANSI C compilers in format
  119. "ddd mmm d hh:nn:ss yyyy" }
  120. function AnsiCDateTime(t: TDateTime): string;
  121. {:Decode three-letter string with name of month to their month number. If string
  122. not match any month name, then is returned 0. For parsing are used predefined
  123. names for English, French and German and names from system locale too.}
  124. function GetMonthNumber(Value: String): integer;
  125. {:Return decoded time from given string. Time must be witch separator ':'. You
  126. can use "hh:mm" or "hh:mm:ss".}
  127. function GetTimeFromStr(Value: string): TDateTime;
  128. {:Decode string representation of TimeZone (CEST, GMT, +0200, -0800, etc.)
  129. to timezone offset.}
  130. function DecodeTimeZone(const Value: string; var Zone: integer): Boolean;
  131. {:Decode string in format "m-d-y" to TDateTime type.}
  132. function GetDateMDYFromStr(Value: string): TDateTime;
  133. {:Decode various string representations of date and time to Tdatetime type.
  134. This function do all timezone corrections too! This function can decode lot of
  135. formats like:
  136. @longcode(#
  137. ddd, d mmm yyyy hh:mm:ss
  138. ddd, d mmm yy hh:mm:ss
  139. ddd, mmm d yyyy hh:mm:ss
  140. ddd mmm dd hh:mm:ss yyyy #)
  141. and more with lot of modifications, include:
  142. @longcode(#
  143. Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123
  144. Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036
  145. Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() Format
  146. #)
  147. Timezone corrections known lot of symbolic timezone names (like CEST, EDT, etc.)
  148. or numeric representation (like +0200). By convention defined in RFC timezone
  149. +0000 is GMT and -0000 is current your system timezone.}
  150. function DecodeRfcDateTime(Value: string): TDateTime;
  151. {:Return current system date and time in UTC timezone.}
  152. function GetUTTime: TDateTime;
  153. {:Set Newdt as current system date and time in UTC timezone. This function work
  154. only if you have administrator rights!}
  155. function SetUTTime(Newdt: TDateTime): Boolean;
  156. {:Return current value of system timer with precizion 1 millisecond. Good for
  157. measure time difference.}
  158. function GetTick: FixedUInt;
  159. {:Return difference between two timestamps. It working fine only for differences
  160. smaller then maxint. (difference must be smaller then 24 days.)}
  161. function TickDelta(TickOld, TickNew: FixedUInt): FixedUInt;
  162. {:Return two characters, which ordinal values represents the value in byte
  163. format. (High-endian)}
  164. function CodeInt(Value: Word): string;
  165. {:Decodes two characters located at "Index" offset position of the "Value"
  166. string to Word values.}
  167. function DecodeInt(const Value: string; Index: integer): Word;
  168. {:Return four characters, which ordinal values represents the value in byte
  169. format. (High-endian)}
  170. function CodeLongInt(Value: LongInt): string;
  171. {:Decodes four characters located at "Index" offset position of the "Value"
  172. string to LongInt values.}
  173. function DecodeLongInt(const Value: string; Index: integer): LongInt;
  174. {:Dump binary buffer stored in a string to a result string.}
  175. function DumpStr(const Buffer: string): string;
  176. {:Dump binary buffer stored in a string to a result string. All bytes with code
  177. of character is written as character, not as hexadecimal value.}
  178. function DumpExStr(const Buffer: string): string;
  179. {:Dump binary buffer stored in a string to a file with DumpFile filename.}
  180. procedure Dump(const Buffer: string; const DumpFile: string);
  181. {:Dump binary buffer stored in a string to a file with DumpFile filename. All
  182. bytes with code of character is written as character, not as hexadecimal value.}
  183. procedure DumpEx(const Buffer: string; const DumpFile: string);
  184. {:Like TrimLeft, but remove only spaces, not control characters!}
  185. function TrimSPLeft(const S: string): string;
  186. {:Like TrimRight, but remove only spaces, not control characters!}
  187. function TrimSPRight(const S: string): string;
  188. {:Like Trim, but remove only spaces, not control characters!}
  189. function TrimSP(const S: string): string;
  190. {:Returns a portion of the "Value" string located to the left of the "Delimiter"
  191. string. If a delimiter is not found, results is original string.}
  192. function SeparateLeft(const Value, Delimiter: string): string;
  193. {:Returns the portion of the "Value" string located to the right of the
  194. "Delimiter" string. If a delimiter is not found, results is original string.}
  195. function SeparateRight(const Value, Delimiter: string): string;
  196. {:Returns parameter value from string in format:
  197. parameter1="value1"; parameter2=value2}
  198. function GetParameter(const Value, Parameter: string): string;
  199. {:parse value string with elements differed by Delimiter into stringlist.}
  200. procedure ParseParametersEx(Value: string; const Delimiter: string; const Parameters: TStrings);
  201. {:parse value string with elements differed by ';' into stringlist.}
  202. procedure ParseParameters(const Value: string; const Parameters: TStrings);
  203. {:Index of string in stringlist with same beginning as Value is returned.}
  204. function IndexByBegin(Value: string; const List: TStrings): integer;
  205. {:Returns only the e-mail portion of an address from the full address format.
  206. i.e. returns 'nobody@@somewhere.com' from '"someone" <nobody@@somewhere.com>'}
  207. function GetEmailAddr(const Value: string): string;
  208. {:Returns only the description part from a full address format. i.e. returns
  209. 'someone' from '"someone" <nobody@@somewhere.com>'}
  210. function GetEmailDesc(Value: string): string;
  211. {:Returns a string with hexadecimal digits representing the corresponding values
  212. of the bytes found in "Value" string.}
  213. function StrToHex(const Value: string): string;
  214. {:Returns a string of binary "Digits" representing "Value".}
  215. function IntToBin(Value: Integer; Digits: Byte): string;
  216. {:Returns an integer equivalent of the binary string in "Value".
  217. (i.e. ('10001010') returns 138)}
  218. function BinToInt(const Value: string): Integer;
  219. {:Parses a URL to its various components.}
  220. function ParseURL(const URL: string; var Prot, User, Pass, Host, Port, Path,
  221. Para: string): string;
  222. {:Replaces all "Search" string values found within "Value" string, with the
  223. "Replace" string value.}
  224. function ReplaceString(Value: string; const Search, Replace: string): string;
  225. {:It is like RPos, but search is from specified possition.}
  226. function RPosEx(const Sub, Value: string; From: integer): Integer;
  227. {:It is like POS function, but from right side of Value string.}
  228. function RPos(const Sub, Value: String): Integer;
  229. {:Like @link(fetch), but working with binary strings, not with text.}
  230. function FetchBin(var Value: string; const Delimiter: string): string;
  231. {:Fetch string from left of Value string.}
  232. function Fetch(var Value: string; const Delimiter: string): string;
  233. {:Fetch string from left of Value string. This function ignore delimitesr inside
  234. quotations.}
  235. function FetchEx(var Value: string; const Delimiter, Quotation: string): string;
  236. {:If string is binary string (contains non-printable characters), then is
  237. returned true.}
  238. function IsBinaryString(const Value: string): Boolean;
  239. {:return position of string terminator in string. If terminator found, then is
  240. returned in terminator parameter.
  241. Possible line terminators are: CRLF, LFCR, CR, LF}
  242. function PosCRLF(const Value: string; var Terminator: string): integer;
  243. {:Delete empty strings from end of stringlist.}
  244. Procedure StringsTrim(const value: TStrings);
  245. {:Like Pos function, buf from given string possition.}
  246. function PosFrom(const SubStr, Value: String; From: integer): integer;
  247. {$IFNDEF CIL}
  248. {:Increase pointer by value.}
  249. function IncPoint(const p: pbyte; Value: integer): pointer;
  250. {$ENDIF}
  251. {:Get string between PairBegin and PairEnd. This function respect nesting.
  252. For example:
  253. @longcode(#
  254. Value is: 'Hi! (hello(yes!))'
  255. pairbegin is: '('
  256. pairend is: ')'
  257. In this case result is: 'hello(yes!)'#)}
  258. function GetBetween(const PairBegin, PairEnd, Value: string): string;
  259. {:Return count of Chr in Value string.}
  260. function CountOfChar(const Value: string; Chr: char): integer;
  261. {:Remove quotation from Value string. If Value is not quoted, then return same
  262. string without any modification. }
  263. function UnquoteStr(const Value: string; Quote: Char): string;
  264. {:Quote Value string. If Value contains some Quote chars, then it is doubled.}
  265. function QuoteStr(const Value: string; Quote: Char): string;
  266. {:Convert lines in stringlist from 'name: value' form to 'name=value' form.}
  267. procedure HeadersToList(const Value: TStrings);
  268. {:Convert lines in stringlist from 'name=value' form to 'name: value' form.}
  269. procedure ListToHeaders(const Value: TStrings);
  270. {:swap bytes in integer.}
  271. function SwapBytes(Value: integer): integer;
  272. {:read string with requested length form stream.}
  273. function ReadStrFromStream(const Stream: TStream; len: integer): ansistring;
  274. {:write string to stream.}
  275. procedure WriteStrToStream(const Stream: TStream; const Value: string); {$IFDEF UNICODE} overload;{$ENDIF}
  276. {$IFDEF UNICODE}
  277. procedure WriteStrToStream(const Stream: TStream; const Value: TSynaBytes); overload;
  278. {$ENDIF}
  279. {:Return filename of new temporary file in Dir (if empty, then default temporary
  280. directory is used) and with optional filename prefix.}
  281. function GetTempFile(const Dir, prefix: TFileName): TFileName;
  282. {:Return padded string. If length is greater, string is truncated. If length is
  283. smaller, string is padded by Pad character.}
  284. function PadString(const Value: string; len: integer; Pad: char): string;
  285. {:XOR each byte in the strings}
  286. function XorString(const Indata1: string; Indata2: string): string;
  287. {:Read header from "Value" stringlist beginning at "Index" position. If header
  288. is Splitted into multiple lines, then this procedure de-split it into one line.}
  289. function NormalizeHeader(Value: TStrings; var Index: Integer): string;
  290. {pf}
  291. {:Search for one of line terminators CR, LF or NUL. Return position of the
  292. line beginning and length of text.}
  293. procedure SearchForLineBreak(var APtr: PChar; AEtx: PChar; out ABol: PChar; out ALength: integer);
  294. {:Skip both line terminators CR LF (if any). Move APtr position forward.}
  295. procedure SkipLineBreak(var APtr: PChar; AEtx: PChar);
  296. {:Skip all blank lines in a buffer starting at APtr and move APtr position forward.}
  297. procedure SkipNullLines(var APtr: PChar; AEtx: PChar);
  298. {:Copy all lines from a buffer starting at APtr to ALines until empty line
  299. or end of the buffer is reached. Move APtr position forward).}
  300. procedure CopyLinesFromStreamUntilNullLine(var APtr: PChar; AEtx: PChar; ALines: TStrings);
  301. {:Copy all lines from a buffer starting at APtr to ALines until ABoundary
  302. or end of the buffer is reached. Move APtr position forward).}
  303. procedure CopyLinesFromStreamUntilBoundary(var APtr: PChar; AEtx: PChar; ALines: TStrings; const ABoundary: string);
  304. {:Search ABoundary in a buffer starting at APtr.
  305. Return beginning of the ABoundary. Move APtr forward behind a trailing CRLF if any).}
  306. function SearchForBoundary(var APtr: PChar; AEtx: PChar; const ABoundary: string): PChar;
  307. {:Compare a text at position ABOL with ABoundary and return position behind the
  308. match (including a trailing CRLF if any).}
  309. function MatchBoundary(ABol, AEtx: PChar; const ABoundary: string): PChar;
  310. {:Compare a text at position ABOL with ABoundary + the last boundary suffix
  311. and return position behind the match (including a trailing CRLF if any).}
  312. function MatchLastBoundary(ABol, AEtx: PChar; const ABoundary: string): PChar;
  313. {:Copy data from a buffer starting at position APtr and delimited by AEtx
  314. position into string. }
  315. function BuildStringFromBuffer(AStx, AEtx: PChar): string;
  316. {/pf}
  317. function CompareString(const Str1, Str2: String; const CaseSensitive: Boolean = false): Boolean;
  318. var
  319. {:can be used for your own months strings for @link(getmonthnumber)}
  320. CustomMonthNames: array[1..12] of string;
  321. implementation
  322. {==============================================================================}
  323. const
  324. MyDayNames: array[1..7] of string =
  325. ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat');
  326. var
  327. MyMonthNames: array[0..6, 1..12] of String =
  328. (
  329. ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', //rewrited by system locales
  330. 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'),
  331. ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', //English
  332. 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'),
  333. ('jan', 'fév', 'mar', 'avr', 'mai', 'jun', //French
  334. 'jul', 'aoû', 'sep', 'oct', 'nov', 'déc'),
  335. ('jan', 'fev', 'mar', 'avr', 'mai', 'jun', //French#2
  336. 'jul', 'aou', 'sep', 'oct', 'nov', 'dec'),
  337. ('Jan', 'Feb', 'Mar', 'Apr', 'Mai', 'Jun', //German
  338. 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'),
  339. ('Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', //German#2
  340. 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'),
  341. ('Led', 'Úno', 'Bøe', 'Dub', 'Kvì', 'Èen', //Czech
  342. 'Èec', 'Srp', 'Záø', 'Øíj', 'Lis', 'Pro')
  343. );
  344. {==============================================================================}
  345. function TimeZoneBias: integer;
  346. {$IF NOT(DEFINED(MSWINDOWS)) and NOT(DEFINED(ULTIBO))}
  347. {$IFNDEF FPC}
  348. var
  349. {$IFDEF POSIX}
  350. t: Posix.SysTypes.time_t;
  351. UT: Posix.time.tm;
  352. {$ELSE}
  353. t: TTime_T;
  354. UT: TUnixTime;
  355. {$ENDIF}
  356. begin
  357. {$IFDEF POSIX}
  358. __time(T);
  359. localtime_r(T, UT);
  360. Result := UT.tm_gmtoff div 60;
  361. {$ELSE}
  362. __time(@T);
  363. localtime_r(@T, UT);
  364. Result := ut.__tm_gmtoff div 60;
  365. {$ENDIF}
  366. {$ELSE}
  367. begin
  368. Result := TZSeconds div 60;
  369. {$ENDIF}
  370. {$ELSE}
  371. var
  372. zoneinfo: TTimeZoneInformation;
  373. bias: Integer;
  374. begin
  375. case GetTimeZoneInformation(Zoneinfo) of
  376. 2:
  377. bias := zoneinfo.Bias + zoneinfo.DaylightBias;
  378. 1:
  379. bias := zoneinfo.Bias + zoneinfo.StandardBias;
  380. else
  381. bias := zoneinfo.Bias;
  382. end;
  383. Result := bias * (-1);
  384. {$ENDIF}
  385. end;
  386. {==============================================================================}
  387. function TimeZone: string;
  388. var
  389. bias: Integer;
  390. h, m: Integer;
  391. begin
  392. bias := TimeZoneBias;
  393. if bias >= 0 then
  394. Result := '+'
  395. else
  396. Result := '-';
  397. bias := Abs(bias);
  398. h := bias div 60;
  399. m := bias mod 60;
  400. Result := Result + Format('%.2d%.2d', [h, m]);
  401. end;
  402. {==============================================================================}
  403. function Rfc822DateTime(t: TDateTime): string;
  404. var
  405. wYear, wMonth, wDay: word;
  406. begin
  407. DecodeDate(t, wYear, wMonth, wDay);
  408. Result := Format('%s, %d %s %s %s', [MyDayNames[DayOfWeek(t)], wDay,
  409. MyMonthNames[1, wMonth], FormatDateTime('yyyy hh":"nn":"ss', t), TimeZone]);
  410. end;
  411. {==============================================================================}
  412. function CDateTime(t: TDateTime): string;
  413. var
  414. wYear, wMonth, wDay: word;
  415. begin
  416. DecodeDate(t, wYear, wMonth, wDay);
  417. Result:= Format('%s %2d %s', [MyMonthNames[1, wMonth], wDay,
  418. FormatDateTime('hh":"nn":"ss', t)]);
  419. end;
  420. {==============================================================================}
  421. function SimpleDateTime(t: TDateTime): string;
  422. begin
  423. Result := FormatDateTime('yymmdd hhnnss', t);
  424. end;
  425. {==============================================================================}
  426. function AnsiCDateTime(t: TDateTime): string;
  427. var
  428. wYear, wMonth, wDay: word;
  429. begin
  430. DecodeDate(t, wYear, wMonth, wDay);
  431. Result := Format('%s %s %d %s', [MyDayNames[DayOfWeek(t)], MyMonthNames[1, wMonth],
  432. wDay, FormatDateTime('hh":"nn":"ss yyyy ', t)]);
  433. end;
  434. {==============================================================================}
  435. function DecodeTimeZone(const Value: string; var Zone: integer): Boolean;
  436. var
  437. x: integer;
  438. zh, zm: integer;
  439. s: string;
  440. begin
  441. Result := false;
  442. s := Value;
  443. if (Pos('+', s) = 1) or (Pos('-',s) = 1) then
  444. begin
  445. if s = '-0000' then
  446. Zone := TimeZoneBias
  447. else
  448. if Length(s) > 4 then
  449. begin
  450. zh := StrToIntDef(s[2] + s[3], 0);
  451. zm := StrToIntDef(s[4] + s[5], 0);
  452. zone := zh * 60 + zm;
  453. if s[1] = '-' then
  454. zone := zone * (-1);
  455. end;
  456. Result := True;
  457. end
  458. else
  459. begin
  460. x := 32767;
  461. if s = 'NZDT' then x := 13;
  462. if s = 'IDLE' then x := 12;
  463. if s = 'NZST' then x := 12;
  464. if s = 'NZT' then x := 12;
  465. if s = 'EADT' then x := 11;
  466. if s = 'GST' then x := 10;
  467. if s = 'JST' then x := 9;
  468. if s = 'CCT' then x := 8;
  469. if s = 'WADT' then x := 8;
  470. if s = 'WAST' then x := 7;
  471. if s = 'ZP6' then x := 6;
  472. if s = 'ZP5' then x := 5;
  473. if s = 'ZP4' then x := 4;
  474. if s = 'BT' then x := 3;
  475. if s = 'EET' then x := 2;
  476. if s = 'MEST' then x := 2;
  477. if s = 'MESZ' then x := 2;
  478. if s = 'SST' then x := 2;
  479. if s = 'FST' then x := 2;
  480. if s = 'CEST' then x := 2;
  481. if s = 'CET' then x := 1;
  482. if s = 'FWT' then x := 1;
  483. if s = 'MET' then x := 1;
  484. if s = 'MEWT' then x := 1;
  485. if s = 'SWT' then x := 1;
  486. if s = 'UT' then x := 0;
  487. if s = 'UTC' then x := 0;
  488. if s = 'GMT' then x := 0;
  489. if s = 'WET' then x := 0;
  490. if s = 'WAT' then x := -1;
  491. if s = 'BST' then x := -1;
  492. if s = 'AT' then x := -2;
  493. if s = 'ADT' then x := -3;
  494. if s = 'AST' then x := -4;
  495. if s = 'EDT' then x := -4;
  496. if s = 'EST' then x := -5;
  497. if s = 'CDT' then x := -5;
  498. if s = 'CST' then x := -6;
  499. if s = 'MDT' then x := -6;
  500. if s = 'MST' then x := -7;
  501. if s = 'PDT' then x := -7;
  502. if s = 'PST' then x := -8;
  503. if s = 'YDT' then x := -8;
  504. if s = 'YST' then x := -9;
  505. if s = 'HDT' then x := -9;
  506. if s = 'AHST' then x := -10;
  507. if s = 'CAT' then x := -10;
  508. if s = 'HST' then x := -10;
  509. if s = 'EAST' then x := -10;
  510. if s = 'NT' then x := -11;
  511. if s = 'IDLW' then x := -12;
  512. if x <> 32767 then
  513. begin
  514. zone := x * 60;
  515. Result := True;
  516. end;
  517. end;
  518. end;
  519. {==============================================================================}
  520. function GetMonthNumber(Value: String): integer;
  521. var
  522. n: integer;
  523. function TestMonth(const Value: String; Index: Integer): Boolean;
  524. var
  525. n: integer;
  526. begin
  527. Result := False;
  528. for n := 0 to 6 do
  529. if Value = AnsiUppercase(MyMonthNames[n, Index]) then
  530. begin
  531. Result := True;
  532. Break;
  533. end;
  534. end;
  535. begin
  536. Result := 0;
  537. Value := AnsiUppercase(Value);
  538. for n := 1 to 12 do
  539. if TestMonth(Value, n) or (Value = AnsiUppercase(CustomMonthNames[n])) then
  540. begin
  541. Result := n;
  542. Break;
  543. end;
  544. end;
  545. {==============================================================================}
  546. function GetTimeFromStr(Value: string): TDateTime;
  547. var
  548. x: integer;
  549. begin
  550. x := rpos(':', Value);
  551. if (x > 0) and ((Length(Value) - x) > 2) then
  552. Value := Copy(Value, 1, x + 2);
  553. Value := ReplaceString(Value, ':', {$IFDEF COMPILER15_UP}FormatSettings.{$ENDIF}TimeSeparator);
  554. Result := -1;
  555. try
  556. Result := StrToTime(Value);
  557. except
  558. on Exception do ;
  559. end;
  560. end;
  561. {==============================================================================}
  562. function GetDateMDYFromStr(Value: string): TDateTime;
  563. var
  564. wYear, wMonth, wDay: word;
  565. s: string;
  566. begin
  567. Result := 0;
  568. s := Fetch(Value, '-');
  569. wMonth := StrToIntDef(s, 12);
  570. s := Fetch(Value, '-');
  571. wDay := StrToIntDef(s, 30);
  572. wYear := StrToIntDef(Value, 1899);
  573. if wYear < 1000 then
  574. if (wYear > 99) then
  575. wYear := wYear + 1900
  576. else
  577. if wYear > 50 then
  578. wYear := wYear + 1900
  579. else
  580. wYear := wYear + 2000;
  581. try
  582. Result := EncodeDate(wYear, wMonth, wDay);
  583. except
  584. on Exception do ;
  585. end;
  586. end;
  587. {==============================================================================}
  588. function DecodeRfcDateTime(Value: string): TDateTime;
  589. var
  590. day, month, year: Word;
  591. zone: integer;
  592. x, y: integer;
  593. s: string;
  594. t: TDateTime;
  595. begin
  596. // ddd, d mmm yyyy hh:mm:ss
  597. // ddd, d mmm yy hh:mm:ss
  598. // ddd, mmm d yyyy hh:mm:ss
  599. // ddd mmm dd hh:mm:ss yyyy
  600. // Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123
  601. // Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036
  602. // Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() Format
  603. Result := 0;
  604. if Value = '' then
  605. Exit;
  606. day := 0;
  607. month := 0;
  608. year := 0;
  609. zone := 0;
  610. Value := ReplaceString(Value, ' -', ' #');
  611. Value := ReplaceString(Value, '-', ' ');
  612. Value := ReplaceString(Value, ' #', ' -');
  613. while Value <> '' do
  614. begin
  615. s := Fetch(Value, ' ');
  616. s := uppercase(s);
  617. // timezone
  618. if DecodetimeZone(s, x) then
  619. begin
  620. zone := x;
  621. continue;
  622. end;
  623. x := StrToIntDef(s, 0);
  624. // day or year
  625. if x > 0 then
  626. if (x < 32) and (day = 0) then
  627. begin
  628. day := x;
  629. continue;
  630. end
  631. else
  632. begin
  633. if (year = 0) and ((month > 0) or (x > 12)) then
  634. begin
  635. year := x;
  636. if year < 32 then
  637. year := year + 2000;
  638. if year < 1000 then
  639. year := year + 1900;
  640. continue;
  641. end;
  642. end;
  643. // time
  644. if rpos(':', s) > Pos(':', s) then
  645. begin
  646. t := GetTimeFromStr(s);
  647. if t <> -1 then
  648. Result := t;
  649. continue;
  650. end;
  651. //timezone daylight saving time
  652. if s = 'DST' then
  653. begin
  654. zone := zone + 60;
  655. continue;
  656. end;
  657. // month
  658. y := GetMonthNumber(s);
  659. if (y > 0) and (month = 0) then
  660. month := y;
  661. end;
  662. if year = 0 then
  663. year := 1980;
  664. if month < 1 then
  665. month := 1;
  666. if month > 12 then
  667. month := 12;
  668. if day < 1 then
  669. day := 1;
  670. x := MonthDays[IsLeapYear(year), month];
  671. if day > x then
  672. day := x;
  673. Result := Result + Encodedate(year, month, day);
  674. zone := zone - TimeZoneBias;
  675. x := zone div 1440;
  676. Result := Result - x;
  677. zone := zone mod 1440;
  678. t := EncodeTime(Abs(zone) div 60, Abs(zone) mod 60, 0, 0);
  679. if zone < 0 then
  680. t := 0 - t;
  681. Result := Result - t;
  682. end;
  683. {==============================================================================}
  684. function GetUTTime: TDateTime;
  685. {$IF DEFINED(MSWINDOWS) or DEFINED(ULTIBO)}
  686. {$IFNDEF FPC}
  687. var
  688. st: TSystemTime;
  689. begin
  690. GetSystemTime(st);
  691. result := SystemTimeToDateTime(st);
  692. {$ELSE}
  693. var
  694. st: SysUtils.TSystemTime;
  695. stw: {$IFNDEF ULTIBO}Windows.TSystemTime{$ELSE}Ultibo.SYSTEMTIME{$ENDIF};
  696. begin
  697. GetSystemTime(stw);
  698. st.Year := stw.wYear;
  699. st.Month := stw.wMonth;
  700. st.Day := stw.wDay;
  701. st.Hour := stw.wHour;
  702. st.Minute := stw.wMinute;
  703. st.Second := stw.wSecond;
  704. st.Millisecond := stw.wMilliseconds;
  705. result := SystemTimeToDateTime(st);
  706. {$ENDIF}
  707. {$ELSE MSWINDOWS}
  708. {$IFNDEF FPC}
  709. var
  710. TV: TTimeVal;
  711. begin
  712. gettimeofday(TV, nil);
  713. Result := UnixDateDelta + (TV.tv_sec + TV.tv_usec / 1000000) / 86400;
  714. {$ELSE FPC}
  715. {$IFDEF UNIX}
  716. var
  717. TV: TimeVal;
  718. begin
  719. fpgettimeofday(@TV, nil);
  720. Result := UnixDateDelta + (TV.tv_sec + TV.tv_usec / 1000000) / 86400;
  721. {$ELSE UNIX}
  722. {$IFDEF OS2}
  723. var
  724. ST: TSystemTime;
  725. begin
  726. GetLocalTime (ST);
  727. Result := SystemTimeToDateTime (ST);
  728. {$ENDIF OS2}
  729. {$ENDIF UNIX}
  730. {$ENDIF FPC}
  731. {$ENDIF MSWINDOWS}
  732. end;
  733. {==============================================================================}
  734. function SetUTTime(Newdt: TDateTime): Boolean;
  735. {$IF DEFINED(MSWINDOWS) or DEFINED(ULTIBO)}
  736. {$IFNDEF FPC}
  737. var
  738. st: TSystemTime;
  739. begin
  740. DateTimeToSystemTime(newdt,st);
  741. Result := SetSystemTime(st);
  742. {$ELSE}
  743. var
  744. st: SysUtils.TSystemTime;
  745. stw: {$IFNDEF ULTIBO}Windows.TSystemTime{$ELSE}Ultibo.SYSTEMTIME{$ENDIF};
  746. begin
  747. DateTimeToSystemTime(newdt,st);
  748. stw.wYear := st.Year;
  749. stw.wMonth := st.Month;
  750. stw.wDay := st.Day;
  751. stw.wHour := st.Hour;
  752. stw.wMinute := st.Minute;
  753. stw.wSecond := st.Second;
  754. stw.wMilliseconds := st.Millisecond;
  755. Result := SetSystemTime(stw);
  756. {$ENDIF}
  757. {$ELSE MSWINDOWS}
  758. {$IFNDEF FPC}
  759. var
  760. TV: TTimeVal;
  761. d: double;
  762. TZ: Ttimezone;
  763. PZ: PTimeZone;
  764. begin
  765. TZ.tz_minuteswest := 0;
  766. TZ.tz_dsttime := 0;
  767. PZ := @TZ;
  768. gettimeofday(TV, PZ);
  769. d := (newdt - UnixDateDelta) * 86400;
  770. TV.tv_sec := trunc(d);
  771. TV.tv_usec := trunc(frac(d) * 1000000);
  772. {$IFNDEF POSIX}
  773. Result := settimeofday(TV, TZ) <> -1;
  774. {$ELSE}
  775. Result := False; // in POSIX settimeofday is not defined? http://www.kernel.org/doc/man-pages/online/pages/man2/gettimeofday.2.html
  776. {$ENDIF}
  777. {$ELSE FPC}
  778. {$IFDEF UNIX}
  779. var
  780. TV: TimeVal;
  781. d: double;
  782. begin
  783. d := (newdt - UnixDateDelta) * 86400;
  784. TV.tv_sec := trunc(d);
  785. TV.tv_usec := trunc(frac(d) * 1000000);
  786. Result := fpsettimeofday(@TV, nil) <> -1;
  787. {$ELSE UNIX}
  788. {$IFDEF OS2}
  789. var
  790. ST: TSystemTime;
  791. begin
  792. DateTimeToSystemTime (NewDT, ST);
  793. SetTime (ST.Hour, ST.Minute, ST.Second, ST.Millisecond div 10);
  794. Result := true;
  795. {$ENDIF OS2}
  796. {$ENDIF UNIX}
  797. {$ENDIF FPC}
  798. {$ENDIF MSWINDOWS}
  799. end;
  800. {==============================================================================}
  801. {$IFNDEF MSWINDOWS}
  802. function GetTick: FixedUInt;
  803. var
  804. Stamp: TTimeStamp;
  805. begin
  806. Stamp := DateTimeToTimeStamp(Now);
  807. Result := Stamp.Time;
  808. end;
  809. {$ELSE}
  810. function GetTick: FixedUInt;
  811. var
  812. tick, freq: TLargeInteger;
  813. {$IFDEF VER100}
  814. x: TLargeInteger;
  815. {$ENDIF}
  816. begin
  817. if Windows.QueryPerformanceFrequency(freq) then
  818. begin
  819. Windows.QueryPerformanceCounter(tick);
  820. {$IFDEF VER100}
  821. x.QuadPart := (tick.QuadPart / freq.QuadPart) * 1000;
  822. Result := x.LowPart;
  823. {$ELSE}
  824. Result := Trunc((tick / freq) * 1000) and High(FixedUInt)
  825. {$ENDIF}
  826. end
  827. else
  828. Result := Windows.GetTickCount;
  829. end;
  830. {$ENDIF}
  831. {==============================================================================}
  832. function TickDelta(TickOld, TickNew: FixedUInt): FixedUInt;
  833. begin
  834. //if DWord is signed type (older Deplhi),
  835. // then it not work properly on differencies larger then maxint!
  836. Result := 0;
  837. if TickOld <> TickNew then
  838. begin
  839. if TickNew < TickOld then
  840. begin
  841. TickNew := TickNew + FixedUInt(MaxInt) + 1;
  842. TickOld := TickOld + FixedUInt(MaxInt) + 1;
  843. end;
  844. Result := TickNew - TickOld;
  845. if TickNew < TickOld then
  846. if Result > 0 then
  847. Result := 0 - Result;
  848. end;
  849. end;
  850. {==============================================================================}
  851. function CodeInt(Value: Word): string;
  852. begin
  853. setlength(result, 2);
  854. Result[1] := char(Value div 256);
  855. Result[2] := char(Value mod 256);
  856. // Result := Char(Value div 256) + Char(Value mod 256)
  857. end;
  858. {==============================================================================}
  859. function DecodeInt(const Value: string; Index: integer): Word;
  860. var
  861. x, y: Byte;
  862. begin
  863. if Length(Value) > Index then
  864. x := Ord(Value[Index])
  865. else
  866. x := 0;
  867. if Length(Value) >= (Index + 1) then
  868. y := Ord(Value[Index + 1])
  869. else
  870. y := 0;
  871. Result := x * 256 + y;
  872. end;
  873. {==============================================================================}
  874. function CodeLongInt(Value: LongInt): string;
  875. var
  876. x, y: word;
  877. begin
  878. // this is fix for negative numbers on systems where longint = integer
  879. x := (Value shr 16) and integer($ffff);
  880. y := Value and integer($ffff);
  881. setlength(result, 4);
  882. Result[1] := char(x div 256);
  883. Result[2] := char(x mod 256);
  884. Result[3] := char(y div 256);
  885. Result[4] := char(y mod 256);
  886. end;
  887. {==============================================================================}
  888. function DecodeLongInt(const Value: string; Index: integer): LongInt;
  889. var
  890. x, y: Byte;
  891. xl, yl: Byte;
  892. begin
  893. if Length(Value) > Index then
  894. x := Ord(Value[Index])
  895. else
  896. x := 0;
  897. if Length(Value) >= (Index + 1) then
  898. y := Ord(Value[Index + 1])
  899. else
  900. y := 0;
  901. if Length(Value) >= (Index + 2) then
  902. xl := Ord(Value[Index + 2])
  903. else
  904. xl := 0;
  905. if Length(Value) >= (Index + 3) then
  906. yl := Ord(Value[Index + 3])
  907. else
  908. yl := 0;
  909. Result := ((x * 256 + y) * 65536) + (xl * 256 + yl);
  910. end;
  911. {==============================================================================}
  912. function DumpStr(const Buffer: string): string;
  913. var
  914. n: Integer;
  915. begin
  916. Result := '';
  917. for n := 1 to Length(Buffer) do
  918. Result := Result + ' +#$' + IntToHex(Ord(Buffer[n]), 2);
  919. end;
  920. {==============================================================================}
  921. function DumpExStr(const Buffer: string): string;
  922. var
  923. n: Integer;
  924. x: Byte;
  925. begin
  926. Result := '';
  927. for n := 1 to Length(Buffer) do
  928. begin
  929. x := Ord(Buffer[n]);
  930. if x in [65..90, 97..122] then
  931. Result := Result + ' +''' + char(x) + ''''
  932. else
  933. Result := Result + ' +#$' + IntToHex(Ord(Buffer[n]), 2);
  934. end;
  935. end;
  936. {==============================================================================}
  937. procedure Dump(const Buffer: string; const DumpFile: string);
  938. var
  939. f: Text;
  940. begin
  941. AssignFile(f, DumpFile);
  942. if FileExists(DumpFile) then
  943. DeleteFile(DumpFile);
  944. Rewrite(f);
  945. try
  946. Writeln(f, DumpStr(Buffer));
  947. finally
  948. CloseFile(f);
  949. end;
  950. end;
  951. {==============================================================================}
  952. procedure DumpEx(const Buffer: string; const DumpFile: string);
  953. var
  954. f: Text;
  955. begin
  956. AssignFile(f, DumpFile);
  957. if FileExists(DumpFile) then
  958. DeleteFile(DumpFile);
  959. Rewrite(f);
  960. try
  961. Writeln(f, DumpExStr(Buffer));
  962. finally
  963. CloseFile(f);
  964. end;
  965. end;
  966. {==============================================================================}
  967. function TrimSPLeft(const S: string): string;
  968. var
  969. I, L: Integer;
  970. begin
  971. Result := '';
  972. if S = '' then
  973. Exit;
  974. L := Length(S);
  975. I := 1;
  976. while (I <= L) and (S[I] = ' ') do
  977. Inc(I);
  978. Result := Copy(S, I, MaxInt);
  979. end;
  980. {==============================================================================}
  981. function TrimSPRight(const S: string): string;
  982. var
  983. I: Integer;
  984. begin
  985. Result := '';
  986. if S = '' then
  987. Exit;
  988. I := Length(S);
  989. while (I > 0) and (S[I] = ' ') do
  990. Dec(I);
  991. Result := Copy(S, 1, I);
  992. end;
  993. {==============================================================================}
  994. function TrimSP(const S: string): string;
  995. begin
  996. Result := TrimSPLeft(s);
  997. Result := TrimSPRight(Result);
  998. end;
  999. {==============================================================================}
  1000. function SeparateLeft(const Value, Delimiter: string): string;
  1001. var
  1002. x: Integer;
  1003. begin
  1004. x := Pos(Delimiter, Value);
  1005. if x < 1 then
  1006. Result := Value
  1007. else
  1008. Result := Copy(Value, 1, x - 1);
  1009. end;
  1010. {==============================================================================}
  1011. function SeparateRight(const Value, Delimiter: string): string;
  1012. var
  1013. x: Integer;
  1014. begin
  1015. x := Pos(Delimiter, Value);
  1016. if x > 0 then
  1017. x := x + Length(Delimiter) - 1;
  1018. Result := Copy(Value, x + 1, Length(Value) - x);
  1019. end;
  1020. {==============================================================================}
  1021. function GetParameter(const Value, Parameter: string): string;
  1022. var
  1023. s: string;
  1024. v: string;
  1025. begin
  1026. Result := '';
  1027. v := Value;
  1028. while v <> '' do
  1029. begin
  1030. s := Trim(FetchEx(v, ';', '"'));
  1031. if Pos(Uppercase(parameter), Uppercase(s)) = 1 then
  1032. begin
  1033. Delete(s, 1, Length(Parameter));
  1034. s := Trim(s);
  1035. if s = '' then
  1036. Break;
  1037. if s[1] = '=' then
  1038. begin
  1039. Result := Trim(SeparateRight(s, '='));
  1040. Result := UnquoteStr(Result, '"');
  1041. break;
  1042. end;
  1043. end;
  1044. end;
  1045. end;
  1046. {==============================================================================}
  1047. procedure ParseParametersEx(Value: string; const Delimiter: string; const
  1048. Parameters: TStrings);
  1049. var
  1050. s: string;
  1051. begin
  1052. Parameters.Clear;
  1053. while Value <> '' do
  1054. begin
  1055. s := Trim(FetchEx(Value, Delimiter, '"'));
  1056. Parameters.Add(s);
  1057. end;
  1058. end;
  1059. {==============================================================================}
  1060. procedure ParseParameters(const Value: string; const Parameters: TStrings);
  1061. begin
  1062. ParseParametersEx(Value, ';', Parameters);
  1063. end;
  1064. {==============================================================================}
  1065. function IndexByBegin(Value: string; const List: TStrings): integer;
  1066. var
  1067. n: integer;
  1068. s: string;
  1069. begin
  1070. Result := -1;
  1071. Value := uppercase(Value);
  1072. for n := 0 to List.Count -1 do
  1073. begin
  1074. s := UpperCase(List[n]);
  1075. if Pos(Value, s) = 1 then
  1076. begin
  1077. Result := n;
  1078. Break;
  1079. end;
  1080. end;
  1081. end;
  1082. {==============================================================================}
  1083. function GetEmailAddr(const Value: string): string;
  1084. var
  1085. s: string;
  1086. begin
  1087. s := SeparateRight(Value, '<');
  1088. s := SeparateLeft(s, '>');
  1089. Result := Trim(s);
  1090. end;
  1091. {==============================================================================}
  1092. function GetEmailDesc(Value: string): string;
  1093. var
  1094. s: string;
  1095. begin
  1096. Value := Trim(Value);
  1097. s := SeparateRight(Value, '"');
  1098. if s <> Value then
  1099. s := SeparateLeft(s, '"')
  1100. else
  1101. begin
  1102. s := SeparateLeft(Value, '<');
  1103. if s = Value then
  1104. begin
  1105. s := SeparateRight(Value, '(');
  1106. if s <> Value then
  1107. s := SeparateLeft(s, ')')
  1108. else
  1109. s := '';
  1110. end;
  1111. end;
  1112. Result := Trim(s);
  1113. end;
  1114. {==============================================================================}
  1115. function StrToHex(const Value: string): string;
  1116. var
  1117. n: Integer;
  1118. begin
  1119. Result := '';
  1120. for n := 1 to Length(Value) do
  1121. Result := Result + IntToHex(Byte(Value[n]), 2);
  1122. Result := LowerCase(Result);
  1123. end;
  1124. {==============================================================================}
  1125. function IntToBin(Value: Integer; Digits: Byte): string;
  1126. var
  1127. x, y, n: Integer;
  1128. begin
  1129. Result := '';
  1130. x := Value;
  1131. repeat
  1132. y := x mod 2;
  1133. x := x div 2;
  1134. if y > 0 then
  1135. Result := '1' + Result
  1136. else
  1137. Result := '0' + Result;
  1138. until x = 0;
  1139. x := Length(Result);
  1140. for n := x to Digits - 1 do
  1141. Result := '0' + Result;
  1142. end;
  1143. {==============================================================================}
  1144. function BinToInt(const Value: string): Integer;
  1145. var
  1146. n: Integer;
  1147. begin
  1148. Result := 0;
  1149. for n := 1 to Length(Value) do
  1150. begin
  1151. if Value[n] = '0' then
  1152. Result := Result * 2
  1153. else
  1154. if Value[n] = '1' then
  1155. Result := Result * 2 + 1
  1156. else
  1157. Break;
  1158. end;
  1159. end;
  1160. {==============================================================================}
  1161. function ParseURL(const URL: string; var Prot, User, Pass, Host, Port, Path,
  1162. Para: string): string;
  1163. var
  1164. x, y: Integer;
  1165. sURL: string;
  1166. s: string;
  1167. s1, s2: string;
  1168. begin
  1169. Prot := 'http';
  1170. User := '';
  1171. Pass := '';
  1172. Host := '';
  1173. Port := '';
  1174. Path := '';
  1175. Para := '';
  1176. x := Pos('://', URL);
  1177. if x > 0 then
  1178. begin
  1179. Prot := SeparateLeft(URL, '://');
  1180. sURL := SeparateRight(URL, '://');
  1181. end
  1182. else
  1183. sURL := URL;
  1184. s := UpperCase(Prot);
  1185. if s = 'HTTP' then
  1186. Port := '80'
  1187. else
  1188. if s = 'HTTPS' then
  1189. Port := '443'
  1190. else
  1191. if s = 'WS' then
  1192. Port := '80'
  1193. else
  1194. if s = 'WSS' then
  1195. Port := '443'
  1196. else
  1197. if s = 'FTP' then
  1198. Port := '21';
  1199. x := Pos('@', sURL);
  1200. y := Pos('/', sURL);
  1201. if (x > 0) and ((x < y) or (y < 1))then
  1202. begin
  1203. s := SeparateLeft(sURL, '@');
  1204. sURL := SeparateRight(sURL, '@');
  1205. x := Pos(':', s);
  1206. if x > 0 then
  1207. begin
  1208. User := SeparateLeft(s, ':');
  1209. Pass := SeparateRight(s, ':');
  1210. end
  1211. else
  1212. User := s;
  1213. end;
  1214. x := Pos('/', sURL);
  1215. if x > 0 then
  1216. begin
  1217. s1 := SeparateLeft(sURL, '/');
  1218. s2 := SeparateRight(sURL, '/');
  1219. end
  1220. else
  1221. begin
  1222. s1 := sURL;
  1223. s2 := '';
  1224. end;
  1225. if Pos('[', s1) = 1 then
  1226. begin
  1227. Host := Separateleft(s1, ']');
  1228. Delete(Host, 1, 1);
  1229. s1 := SeparateRight(s1, ']');
  1230. if Pos(':', s1) = 1 then
  1231. Port := SeparateRight(s1, ':');
  1232. end
  1233. else
  1234. begin
  1235. x := Pos(':', s1);
  1236. if x > 0 then
  1237. begin
  1238. Host := SeparateLeft(s1, ':');
  1239. Port := SeparateRight(s1, ':');
  1240. end
  1241. else
  1242. Host := s1;
  1243. end;
  1244. Result := '/' + s2;
  1245. x := Pos('?', s2);
  1246. if x > 0 then
  1247. begin
  1248. Path := '/' + SeparateLeft(s2, '?');
  1249. Para := SeparateRight(s2, '?');
  1250. end
  1251. else
  1252. Path := '/' + s2;
  1253. if Host = '' then
  1254. Host := 'localhost';
  1255. end;
  1256. {==============================================================================}
  1257. function ReplaceString(Value: string; const Search, Replace: string): string;
  1258. var
  1259. x, l, ls, lr: Integer;
  1260. begin
  1261. if (Value = '') or (Search = '') then
  1262. begin
  1263. Result := Value;
  1264. Exit;
  1265. end;
  1266. ls := Length(Search);
  1267. lr := Length(Replace);
  1268. Result := '';
  1269. x := Pos(Search, Value);
  1270. while x > 0 do
  1271. begin
  1272. {$IFNDEF CIL}
  1273. l := Length(Result);
  1274. SetLength(Result, l + x - 1);
  1275. Move(Pointer(Value)^, Pointer(@Result[l + 1])^, x - 1);
  1276. {$ELSE}
  1277. Result:=Result+Copy(Value,1,x-1);
  1278. {$ENDIF}
  1279. {$IFNDEF CIL}
  1280. l := Length(Result);
  1281. SetLength(Result, l + lr);
  1282. Move(Pointer(Replace)^, Pointer(@Result[l + 1])^, lr);
  1283. {$ELSE}
  1284. Result:=Result+Replace;
  1285. {$ENDIF}
  1286. Delete(Value, 1, x - 1 + ls);
  1287. x := Pos(Search, Value);
  1288. end;
  1289. Result := Result + Value;
  1290. end;
  1291. {==============================================================================}
  1292. function RPosEx(const Sub, Value: string; From: integer): Integer;
  1293. var
  1294. n: Integer;
  1295. l: Integer;
  1296. begin
  1297. result := 0;
  1298. l := Length(Sub);
  1299. for n := From - l + 1 downto 1 do
  1300. begin
  1301. if Copy(Value, n, l) = Sub then
  1302. begin
  1303. result := n;
  1304. break;
  1305. end;
  1306. end;
  1307. end;
  1308. {==============================================================================}
  1309. function RPos(const Sub, Value: String): Integer;
  1310. begin
  1311. Result := RPosEx(Sub, Value, Length(Value));
  1312. end;
  1313. {==============================================================================}
  1314. function FetchBin(var Value: string; const Delimiter: string): string;
  1315. var
  1316. s: string;
  1317. begin
  1318. Result := SeparateLeft(Value, Delimiter);
  1319. s := SeparateRight(Value, Delimiter);
  1320. if s = Value then
  1321. Value := ''
  1322. else
  1323. Value := s;
  1324. end;
  1325. {==============================================================================}
  1326. function Fetch(var Value: string; const Delimiter: string): string;
  1327. begin
  1328. Result := FetchBin(Value, Delimiter);
  1329. Result := TrimSP(Result);
  1330. Value := TrimSP(Value);
  1331. end;
  1332. {==============================================================================}
  1333. function FetchEx(var Value: string; const Delimiter, Quotation: string): string;
  1334. var
  1335. b: Boolean;
  1336. begin
  1337. Result := '';
  1338. b := False;
  1339. while Length(Value) > 0 do
  1340. begin
  1341. if b then
  1342. begin
  1343. if Pos(Quotation, Value) = 1 then
  1344. b := False;
  1345. Result := Result + Value[1];
  1346. Delete(Value, 1, 1);
  1347. end
  1348. else
  1349. begin
  1350. if Pos(Delimiter, Value) = 1 then
  1351. begin
  1352. Delete(Value, 1, Length(delimiter));
  1353. break;
  1354. end;
  1355. b := Pos(Quotation, Value) = 1;
  1356. Result := Result + Value[1];
  1357. Delete(Value, 1, 1);
  1358. end;
  1359. end;
  1360. end;
  1361. {==============================================================================}
  1362. function IsBinaryString(const Value: string): Boolean;
  1363. var
  1364. n: integer;
  1365. begin
  1366. Result := False;
  1367. for n := 1 to Length(Value) do
  1368. if CharInSet(Value[n], [#0 .. #8, #10 .. #31]) then
  1369. // ignore null-terminated strings
  1370. if not((n = Length(Value)) and (Value[n] = char(#0))) then
  1371. begin
  1372. Result := True;
  1373. Break;
  1374. end;
  1375. end;
  1376. {==============================================================================}
  1377. function PosCRLF(const Value: string; var Terminator: string): integer;
  1378. var
  1379. n, l: integer;
  1380. begin
  1381. Result := -1;
  1382. Terminator := '';
  1383. l := length(value);
  1384. for n := 1 to L do
  1385. if CharInSet(Value[n], [#$0d, #$0a]) then
  1386. begin
  1387. Result := n;
  1388. Terminator := Value[n];
  1389. if n <> l then
  1390. case value[n] of
  1391. #$0d:
  1392. if value[n + 1] = #$0a then
  1393. Terminator := #$0d + #$0a;
  1394. #$0a:
  1395. if value[n + 1] = #$0d then
  1396. Terminator := #$0a + #$0d;
  1397. end;
  1398. Break;
  1399. end;
  1400. end;
  1401. {==============================================================================}
  1402. Procedure StringsTrim(const Value: TStrings);
  1403. var
  1404. n: integer;
  1405. begin
  1406. for n := Value.Count - 1 downto 0 do
  1407. if Value[n] = '' then
  1408. Value.Delete(n)
  1409. else
  1410. Break;
  1411. end;
  1412. {==============================================================================}
  1413. function PosFrom(const SubStr, Value: String; From: integer): integer;
  1414. var
  1415. ls,lv: integer;
  1416. begin
  1417. Result := 0;
  1418. ls := Length(SubStr);
  1419. lv := Length(Value);
  1420. if (ls = 0) or (lv = 0) then
  1421. Exit;
  1422. if From < 1 then
  1423. From := 1;
  1424. while (ls + from - 1) <= (lv) do
  1425. begin
  1426. {$IFNDEF CIL}
  1427. if CompareMem(@SubStr[1],@Value[from],ls) then
  1428. {$ELSE}
  1429. if SubStr = copy(Value, from, ls) then
  1430. {$ENDIF}
  1431. begin
  1432. result := from;
  1433. break;
  1434. end
  1435. else
  1436. inc(from);
  1437. end;
  1438. end;
  1439. {==============================================================================}
  1440. {$IFNDEF CIL}
  1441. function IncPoint(const p: pbyte; Value: integer): pointer;
  1442. begin
  1443. Result := p;
  1444. Inc(pbyte(Result), Value);
  1445. end;
  1446. {$ENDIF}
  1447. {==============================================================================}
  1448. //improved by 'DoggyDawg'
  1449. function GetBetween(const PairBegin, PairEnd, Value: string): string;
  1450. var
  1451. n: integer;
  1452. x: integer;
  1453. s: string;
  1454. lenBegin: integer;
  1455. lenEnd: integer;
  1456. str: string;
  1457. max: integer;
  1458. begin
  1459. lenBegin := Length(PairBegin);
  1460. lenEnd := Length(PairEnd);
  1461. n := Length(Value);
  1462. if (Value = PairBegin + PairEnd) then
  1463. begin
  1464. Result := '';//nothing between
  1465. exit;
  1466. end;
  1467. if (n < lenBegin + lenEnd) then
  1468. begin
  1469. Result := Value;
  1470. exit;
  1471. end;
  1472. s := SeparateRight(Value, PairBegin);
  1473. if (s = Value) then
  1474. begin
  1475. Result := Value;
  1476. exit;
  1477. end;
  1478. n := Pos(PairEnd, s);
  1479. if (n = 0) then
  1480. begin
  1481. Result := Value;
  1482. exit;
  1483. end;
  1484. Result := '';
  1485. x := 1;
  1486. max := Length(s) - lenEnd + 1;
  1487. for n := 1 to max do
  1488. begin
  1489. str := copy(s, n, lenEnd);
  1490. if (str = PairEnd) then
  1491. begin
  1492. Dec(x);
  1493. if (x <= 0) then
  1494. Break;
  1495. end;
  1496. str := copy(s, n, lenBegin);
  1497. if (str = PairBegin) then
  1498. Inc(x);
  1499. Result := Result + s[n];
  1500. end;
  1501. end;
  1502. {==============================================================================}
  1503. function CountOfChar(const Value: string; Chr: char): integer;
  1504. var
  1505. n: integer;
  1506. begin
  1507. Result := 0;
  1508. for n := 1 to Length(Value) do
  1509. if Value[n] = chr then
  1510. Inc(Result);
  1511. end;
  1512. {==============================================================================}
  1513. // ! do not use AnsiExtractQuotedStr, it's very buggy and can crash application!
  1514. function UnquoteStr(const Value: string; Quote: Char): string;
  1515. var
  1516. n: integer;
  1517. inq, dq: Boolean;
  1518. c, cn: char;
  1519. begin
  1520. Result := '';
  1521. if Value = '' then
  1522. Exit;
  1523. if Value = Quote + Quote then
  1524. Exit;
  1525. inq := False;
  1526. dq := False;
  1527. for n := 1 to Length(Value) do
  1528. begin
  1529. c := Value[n];
  1530. if n <> Length(Value) then
  1531. cn := Value[n + 1]
  1532. else
  1533. cn := #0;
  1534. if c = quote then
  1535. if dq then
  1536. dq := False
  1537. else
  1538. if not inq then
  1539. inq := True
  1540. else
  1541. if cn = quote then
  1542. begin
  1543. Result := Result + Quote;
  1544. dq := True;
  1545. end
  1546. else
  1547. inq := False
  1548. else
  1549. Result := Result + c;
  1550. end;
  1551. end;
  1552. {==============================================================================}
  1553. function QuoteStr(const Value: string; Quote: Char): string;
  1554. var
  1555. n: integer;
  1556. begin
  1557. Result := '';
  1558. for n := 1 to length(value) do
  1559. begin
  1560. Result := result + Value[n];
  1561. if value[n] = Quote then
  1562. Result := Result + Quote;
  1563. end;
  1564. Result := Quote + Result + Quote;
  1565. end;
  1566. {==============================================================================}
  1567. procedure HeadersToList(const Value: TStrings);
  1568. var
  1569. n, x, y: integer;
  1570. s: string;
  1571. begin
  1572. for n := 0 to Value.Count -1 do
  1573. begin
  1574. s := Value[n];
  1575. x := Pos(':', s);
  1576. if x > 0 then
  1577. begin
  1578. y:= Pos('=',s);
  1579. if not ((y > 0) and (y < x)) then
  1580. begin
  1581. s[x] := '=';
  1582. Value[n] := s;
  1583. end;
  1584. end;
  1585. end;
  1586. end;
  1587. {==============================================================================}
  1588. procedure ListToHeaders(const Value: TStrings);
  1589. var
  1590. n, x: integer;
  1591. s: string;
  1592. begin
  1593. for n := 0 to Value.Count -1 do
  1594. begin
  1595. s := Value[n];
  1596. x := Pos('=', s);
  1597. if x > 0 then
  1598. begin
  1599. s[x] := ':';
  1600. Value[n] := s;
  1601. end;
  1602. end;
  1603. end;
  1604. {==============================================================================}
  1605. function SwapBytes(Value: integer): integer;
  1606. var
  1607. S: string;
  1608. x, y, xl, yl: Byte;
  1609. begin
  1610. s := CodeLongInt(Value);
  1611. x := Ord(s[4]);
  1612. y := Ord(s[3]);
  1613. xl := Ord(s[2]);
  1614. yl := Ord(s[1]);
  1615. Result := ((x * 256 + y) * 65536) + (xl * 256 + yl);
  1616. end;
  1617. {==============================================================================}
  1618. function ReadStrFromStream(const Stream: TStream; len: integer): ansistring;
  1619. begin
  1620. SetLength(Result, Min(len, Stream.Size));
  1621. Stream.ReadBuffer(Result[1], Length(Result));
  1622. end;
  1623. {==============================================================================}
  1624. procedure WriteStrToStream(const Stream: TStream; const Value: string);
  1625. {$IFDEF CIL}
  1626. var
  1627. buf: Array of Byte;
  1628. {$ENDIF}
  1629. begin
  1630. {$IFDEF CIL}
  1631. buf := BytesOf(Value);
  1632. Stream.Write(buf,length(Value));
  1633. {$ELSE}
  1634. {$IFDEF UNICODE}
  1635. Stream.Write(MarshaledAString(TMarshal.AsAnsi(Value))^, Length(Value));
  1636. {$ELSE}
  1637. Stream.Write(PAnsiChar(Value)^, Length(Value));
  1638. {$ENDIF}
  1639. {$ENDIF}
  1640. end;
  1641. {$IFDEF UNICODE}
  1642. procedure WriteStrToStream(const Stream: TStream; const Value: TSynaBytes);
  1643. begin
  1644. stream.WriteData(Value.Bytes, Value.Length);
  1645. end;
  1646. {$ENDIF}
  1647. {==============================================================================}
  1648. {$IFDEF POSIX}
  1649. function tempnam(const Path: PChar; const prefix: PChar): PChar; cdecl;
  1650. external libc name _PU + 'tempnam';
  1651. {$ENDIF}
  1652. function GetTempFile(const Dir, prefix: TFileName): TFileName;
  1653. {$IFNDEF FPC}
  1654. {$IFDEF MSWINDOWS}
  1655. var
  1656. Path: TFileName;
  1657. x: integer;
  1658. {$ENDIF}
  1659. {$ENDIF}
  1660. begin
  1661. {$IFDEF FPC}
  1662. Result := GetTempFileName(Dir, Prefix);
  1663. {$ELSE}
  1664. {$IFNDEF MSWINDOWS}
  1665. Result := tempnam(Pointer(Dir), Pointer(prefix));
  1666. {$ELSE}
  1667. {$IFDEF CIL}
  1668. Result := System.IO.Path.GetTempFileName;
  1669. {$ELSE}
  1670. if Dir = '' then
  1671. begin
  1672. Path := StringOfChar(#0, MAX_PATH);
  1673. GetTempPath(Length(Path), PChar(Path));
  1674. Path := PChar(Path);
  1675. end
  1676. else
  1677. Path := Dir;
  1678. x := Length(Path);
  1679. if Path[x] <> '\' then
  1680. Path := Path + '\';
  1681. Result := StringOfChar(#0, MAX_PATH);
  1682. GetTempFileName(PChar(Path), PChar(Prefix), 0, PChar(Result));
  1683. Result := PChar(Result);
  1684. SetFileattributes(PChar(Result), GetFileAttributes(PChar(Result)) or FILE_ATTRIBUTE_TEMPORARY);
  1685. {$ENDIF}
  1686. {$ENDIF}
  1687. {$ENDIF}
  1688. end;
  1689. {==============================================================================}
  1690. function PadString(const Value: string; len: integer; Pad: char): string;
  1691. begin
  1692. if length(value) >= len then
  1693. Result := Copy(value, 1, len)
  1694. else
  1695. Result := Value + StringOfChar(Pad, len - length(value));
  1696. end;
  1697. {==============================================================================}
  1698. function XorString(const Indata1: string; Indata2: string): string;
  1699. var
  1700. i: integer;
  1701. begin
  1702. Indata2 := PadString(Indata2, length(Indata1), #0);
  1703. Result := '';
  1704. for i := 1 to length(Indata1) do
  1705. Result := Result + char(ord(Indata1[i]) xor ord(Indata2[i]));
  1706. end;
  1707. {==============================================================================}
  1708. function NormalizeHeader(Value: TStrings; var Index: Integer): string;
  1709. var
  1710. s, t: string;
  1711. n: Integer;
  1712. begin
  1713. s := Value[Index];
  1714. Inc(Index);
  1715. if s <> '' then
  1716. while (Value.Count - 1) > Index do
  1717. begin
  1718. t := Value[Index];
  1719. if t = '' then
  1720. Break;
  1721. for n := 1 to Length(t) do
  1722. if t[n] = #9 then
  1723. t[n] := ' ';
  1724. if not(CharInSet(char(t[1]), [' ', '"', ':', '='])) then
  1725. Break
  1726. else
  1727. begin
  1728. s := s + ' ' + Trim(t);
  1729. Inc(Index);
  1730. end;
  1731. end;
  1732. Result := TrimRight(s);
  1733. end;
  1734. {==============================================================================}
  1735. {pf}
  1736. procedure SearchForLineBreak(var APtr: PChar; AEtx: PChar; out ABol: PChar;
  1737. out ALength: integer);
  1738. begin
  1739. ABol := APtr;
  1740. while (APtr < AEtx) and not(CharInSet(APtr^, [#0, #10, #13])) do
  1741. Inc(APtr);
  1742. ALength := APtr - ABol;
  1743. end;
  1744. {/pf}
  1745. {pf}
  1746. procedure SkipLineBreak(var APtr: PChar; AEtx: PChar);
  1747. begin
  1748. if (APtr < AEtx) and (APtr^ = #13) then
  1749. inc(APtr);
  1750. if (APtr < AEtx) and (APtr^ = #10) then
  1751. inc(APtr);
  1752. end;
  1753. {/pf}
  1754. {pf}
  1755. procedure SkipNullLines(var APtr: PChar; AEtx: PChar);
  1756. var
  1757. bol: PChar;
  1758. lng: integer;
  1759. begin
  1760. while (APtr < AEtx) do
  1761. begin
  1762. SearchForLineBreak(APtr,AEtx,bol,lng);
  1763. SkipLineBreak(APtr,AEtx);
  1764. if lng>0 then
  1765. begin
  1766. APtr := bol;
  1767. Break;
  1768. end;
  1769. end;
  1770. end;
  1771. {/pf}
  1772. {pf}
  1773. procedure CopyLinesFromStreamUntilNullLine(var APtr: PChar; AEtx: PChar; ALines: TStrings);
  1774. var
  1775. bol: PChar;
  1776. lng: integer;
  1777. s: string;
  1778. begin
  1779. // Copying until body separator will be reached
  1780. while (APtr<AEtx) and (APtr^<>#0) do
  1781. begin
  1782. SearchForLineBreak(APtr,AEtx,bol,lng);
  1783. SkipLineBreak(APtr,AEtx);
  1784. if lng=0 then
  1785. Break;
  1786. SetString(s,bol,lng);
  1787. ALines.Add(s);
  1788. end;
  1789. end;
  1790. {/pf}
  1791. {pf}
  1792. procedure CopyLinesFromStreamUntilBoundary(var APtr: PChar; AEtx: PChar; ALines: TStrings; const ABoundary: string);
  1793. var
  1794. bol: PChar;
  1795. lng: integer;
  1796. s: string;
  1797. //BackStop: string;
  1798. eob1: PChar;
  1799. eob2: PChar;
  1800. begin
  1801. //BackStop := '--'+ABoundary;
  1802. eob2 := nil;
  1803. // Copying until Boundary will be reached
  1804. while (APtr<AEtx) do
  1805. begin
  1806. SearchForLineBreak(APtr,AEtx,bol,lng);
  1807. SkipLineBreak(APtr,AEtx);
  1808. eob1 := MatchBoundary(bol,APtr,ABoundary);
  1809. if Assigned(eob1) then
  1810. eob2 := MatchLastBoundary(bol,AEtx,ABoundary);
  1811. if Assigned(eob2) then
  1812. begin
  1813. APtr := eob2;
  1814. Break;
  1815. end
  1816. else if Assigned(eob1) then
  1817. begin
  1818. APtr := eob1;
  1819. Break;
  1820. end
  1821. else
  1822. begin
  1823. SetString(s,bol,lng);
  1824. ALines.Add(s);
  1825. end;
  1826. end;
  1827. end;
  1828. {/pf}
  1829. {pf}
  1830. function SearchForBoundary(var APtr: PChar; AEtx: PChar; const ABoundary: string): PChar;
  1831. var
  1832. eob: PChar;
  1833. Step: integer;
  1834. begin
  1835. Result := nil;
  1836. // Moving Aptr position forward until boundary will be reached
  1837. while (APtr<AEtx) do
  1838. begin
  1839. if strlcomp(APtr,#13#10'--',4)=0 then
  1840. begin
  1841. eob := MatchBoundary(APtr,AEtx,ABoundary);
  1842. Step := 4;
  1843. end
  1844. else if strlcomp(APtr,'--',2)=0 then
  1845. begin
  1846. eob := MatchBoundary(APtr,AEtx,ABoundary);
  1847. Step := 2;
  1848. end
  1849. else
  1850. begin
  1851. eob := nil;
  1852. Step := 1;
  1853. end;
  1854. if Assigned(eob) then
  1855. begin
  1856. Result := APtr; // boundary beginning
  1857. APtr := eob; // boundary end
  1858. exit;
  1859. end
  1860. else
  1861. inc(APtr,Step);
  1862. end;
  1863. end;
  1864. {/pf}
  1865. {pf}
  1866. function MatchBoundary(ABol, AEtx: PChar; const ABoundary: string): PChar;
  1867. var
  1868. MatchPos: PChar;
  1869. Lng: integer;
  1870. begin
  1871. Result := nil;
  1872. MatchPos := ABol;
  1873. Lng := length(ABoundary);
  1874. if (MatchPos + 2 + lng) > AEtx then
  1875. exit;
  1876. if strlcomp(MatchPos, #13#10, 2) = 0 then
  1877. inc(MatchPos,2);
  1878. if (MatchPos + 2 + lng) > AEtx then
  1879. exit;
  1880. if strlcomp(MatchPos,'--',2)<>0 then
  1881. exit;
  1882. inc(MatchPos,2);
  1883. if strlcomp(MatchPos, PChar(ABoundary), lng) <> 0 then
  1884. exit;
  1885. inc(MatchPos,Lng);
  1886. if ((MatchPos+2)<=AEtx) and (strlcomp(MatchPos,#13#10,2)=0) then
  1887. inc(MatchPos,2);
  1888. Result := MatchPos;
  1889. end;
  1890. {/pf}
  1891. {pf}
  1892. function MatchLastBoundary(ABol, AEtx: PChar; const ABoundary: string): PChar;
  1893. var
  1894. MatchPos: PChar;
  1895. begin
  1896. Result := nil;
  1897. MatchPos := MatchBoundary(ABol, AEtx, ABoundary);
  1898. if not Assigned(MatchPos) then
  1899. exit;
  1900. if strlcomp(MatchPos,'--',2)<>0 then
  1901. exit;
  1902. inc(MatchPos,2);
  1903. if (MatchPos+2<=AEtx) and (strlcomp(MatchPos,#13#10,2)=0) then
  1904. inc(MatchPos,2);
  1905. Result := MatchPos;
  1906. end;
  1907. {/pf}
  1908. {pf}
  1909. function BuildStringFromBuffer(AStx, AEtx: PChar): string;
  1910. var
  1911. lng: integer;
  1912. begin
  1913. Lng := 0;
  1914. if Assigned(AStx) and Assigned(AEtx) then
  1915. begin
  1916. Lng := AEtx-AStx;
  1917. if Lng<0 then
  1918. Lng := 0;
  1919. end;
  1920. SetString(Result,AStx,lng);
  1921. end;
  1922. {/pf}
  1923. function CompareString(const Str1, Str2: String;
  1924. const CaseSensitive: Boolean = false): Boolean;
  1925. begin
  1926. if not CaseSensitive then
  1927. Result := Pos(LowerCase(Str1), LowerCase(Str2)) > 0
  1928. else
  1929. Result := Pos(Str1, Str2) > 0;
  1930. end;
  1931. {==============================================================================}
  1932. var
  1933. n: integer;
  1934. begin
  1935. for n := 1 to 12 do
  1936. begin
  1937. CustomMonthNames[n] := {$IFDEF COMPILER15_UP}FormatSettings.{$ENDIF}ShortMonthNames[n];
  1938. MyMonthNames[0, n] := {$IFDEF COMPILER15_UP}FormatSettings.{$ENDIF}ShortMonthNames[n];
  1939. end;
  1940. end.