source: trunk/Packages/synapse/source/lib/synautil.pas

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