{----------------------------------------------------------------------------- The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/MPL-1.1.html Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for the specific language governing rights and limitations under the License. The Original Code is: WStrUtils.PAS, released on 2004-01-25. The Initial Developers of the Original Code are Andreas Hausladen and Mike Lischke (WideQuotedStr & WideExtractQuotedStr from Unicode.pas). All Rights Reserved. Contributors: Robert Marquardt (marquardt) Robert Rossmair (rrossmair) You may retrieve the latest version of this file at the Project JEDI's JCL home page, located at http://jcl.sourceforge.net This is a lightweight Unicode unit. For more features use JclUnicode. Known Issues: -----------------------------------------------------------------------------} unit JclWideStrings; {$I jcl.inc} interface uses Classes, SysUtils; const // definitions of often used characters: // Note: Use them only for tests of a certain character not to determine character // classes (like white spaces) as in Unicode are often many code points defined // being in a certain class. Hence your best option is to use the various // UnicodeIs* functions. WideNull = WideChar(#0); WideTabulator = WideChar(#9); WideSpace = WideChar(#32); // logical line breaks WideLF = WideChar(#10); WideLineFeed = WideChar(#10); WideVerticalTab = WideChar(#11); WideFormFeed = WideChar(#12); WideCR = WideChar(#13); WideCarriageReturn = WideChar(#13); WideCRLF: WideString = #13#10; WideLineSeparator = WideChar($2028); WideParagraphSeparator = WideChar($2029); BOM_LSB_FIRST = WideChar($FEFF); BOM_MSB_FIRST = WideChar($FFFE); type TWideFileOptionsType = ( foAnsiFile, // loads/writes an ANSI file foUnicodeLB // reads/writes BOM_LSB_FIRST/BOM_MSB_FIRST ); TWideFileOptions = set of TWideFileOptionsType; TSearchFlag = ( sfCaseSensitive, // match letter case sfIgnoreNonSpacing, // ignore non-spacing characters in search sfSpaceCompress, // handle several consecutive white spaces as one white space // (this applies to the pattern as well as the search text) sfWholeWordOnly // match only text at end/start and/or surrounded by white spaces ); TSearchFlags = set of TSearchFlag; TWStrings = class; TWStringList = class; TWStringListSortCompare = function(List: TWStringList; Index1, Index2: Integer): Integer; TWStrings = class(TPersistent) private FDelimiter: WideChar; FQuoteChar: WideChar; FNameValueSeparator: WideChar; FLineSeparator: WideString; FUpdateCount: Integer; function GetCommaText: WideString; function GetDelimitedText: WideString; function GetName(Index: Integer): WideString; function GetValue(const Name: WideString): WideString; procedure ReadData(Reader: TReader); procedure SetCommaText(const Value: WideString); procedure SetDelimitedText(const Value: WideString); procedure SetValue(const Name, Value: WideString); procedure WriteData(Writer: TWriter); function GetValueFromIndex(Index: Integer): WideString; procedure SetValueFromIndex(Index: Integer; const Value: WideString); protected procedure DefineProperties(Filer: TFiler); override; function ExtractName(const S: WideString): WideString; function GetP(Index: Integer): PWideString; virtual; abstract; function Get(Index: Integer): WideString; function GetCapacity: Integer; virtual; function GetCount: Integer; virtual; abstract; function GetObject(Index: Integer): TObject; virtual; function GetTextStr: WideString; virtual; procedure Put(Index: Integer; const S: WideString); virtual; abstract; procedure PutObject(Index: Integer; AObject: TObject); virtual; abstract; procedure SetCapacity(NewCapacity: Integer); virtual; procedure SetTextStr(const Value: WideString); virtual; procedure SetUpdateState(Updating: Boolean); virtual; property UpdateCount: Integer read FUpdateCount; function CompareStrings(const S1, S2: WideString): Integer; virtual; procedure AssignTo(Dest: TPersistent); override; public constructor Create; function Add(const S: WideString): Integer; virtual; function AddObject(const S: WideString; AObject: TObject): Integer; virtual; procedure Append(const S: WideString); procedure AddStrings(Strings: TWStrings); overload; virtual; procedure AddStrings(Strings: TStrings); overload; virtual; procedure Assign(Source: TPersistent); override; function CreateAnsiStringList: TStrings; procedure AddStringsTo(Dest: TStrings); virtual; procedure BeginUpdate; procedure Clear; virtual; abstract; procedure Delete(Index: Integer); virtual; abstract; procedure EndUpdate; function Equals(Strings: TWStrings): Boolean; overload; function Equals(Strings: TStrings): Boolean; overload; procedure Exchange(Index1, Index2: Integer); virtual; function GetText: PWideChar; virtual; function IndexOf(const S: WideString): Integer; virtual; function IndexOfName(const Name: WideString): Integer; virtual; function IndexOfObject(AObject: TObject): Integer; virtual; procedure Insert(Index: Integer; const S: WideString); virtual; procedure InsertObject(Index: Integer; const S: WideString; AObject: TObject); virtual; procedure LoadFromFile(const FileName: AnsiString; WideFileOptions: TWideFileOptions = []); virtual; procedure LoadFromStream(Stream: TStream; WideFileOptions: TWideFileOptions = []); virtual; procedure Move(CurIndex, NewIndex: Integer); virtual; procedure SaveToFile(const FileName: AnsiString; WideFileOptions: TWideFileOptions = []); virtual; procedure SaveToStream(Stream: TStream; WideFileOptions: TWideFileOptions = []); virtual; procedure SetText(Text: PWideChar); virtual; function GetDelimitedTextEx(ADelimiter, AQuoteChar: WideChar): WideString; procedure SetDelimitedTextEx(ADelimiter, AQuoteChar: WideChar; const Value: WideString); property Capacity: Integer read GetCapacity write SetCapacity; property CommaText: WideString read GetCommaText write SetCommaText; property Count: Integer read GetCount; property Delimiter: WideChar read FDelimiter write FDelimiter; property DelimitedText: WideString read GetDelimitedText write SetDelimitedText; property Names[Index: Integer]: WideString read GetName; property Objects[Index: Integer]: TObject read GetObject write PutObject; property QuoteChar: WideChar read FQuoteChar write FQuoteChar; property Values[const Name: WideString]: WideString read GetValue write SetValue; property ValueFromIndex[Index: Integer]: WideString read GetValueFromIndex write SetValueFromIndex; property NameValueSeparator: WideChar read FNameValueSeparator write FNameValueSeparator; property LineSeparator: WideString read FLineSeparator write FLineSeparator; property PStrings[Index: Integer]: PWideString read GetP; property Strings[Index: Integer]: WideString read Get write Put; default; property Text: WideString read GetTextStr write SetTextStr; end; // do not replace by JclUnicode.TWideStringList (speed and size issue) PWStringItem = ^TWStringItem; TWStringItem = record FString: WideString; FObject: TObject; end; TWStringList = class(TWStrings) private FList: TList; FSorted: Boolean; FDuplicates: TDuplicates; FCaseSensitive: Boolean; FOnChange: TNotifyEvent; FOnChanging: TNotifyEvent; procedure SetSorted(Value: Boolean); procedure SetCaseSensitive(const Value: Boolean); protected function GetItem(Index: Integer): PWStringItem; procedure Changed; virtual; procedure Changing; virtual; function GetP(Index: Integer): PWideString; override; function GetCapacity: Integer; override; function GetCount: Integer; override; function GetObject(Index: Integer): TObject; override; procedure Put(Index: Integer; const Value: WideString); override; procedure PutObject(Index: Integer; AObject: TObject); override; procedure SetCapacity(NewCapacity: Integer); override; procedure SetUpdateState(Updating: Boolean); override; function CompareStrings(const S1, S2: WideString): Integer; override; public constructor Create; destructor Destroy; override; function AddObject(const S: WideString; AObject: TObject): Integer; override; procedure Clear; override; procedure Delete(Index: Integer); override; procedure Exchange(Index1, Index2: Integer); override; function Find(const S: WideString; var Index: Integer): Boolean; virtual; // Find() also works with unsorted lists function IndexOf(const S: WideString): Integer; override; procedure InsertObject(Index: Integer; const S: WideString; AObject: TObject); override; procedure Sort; virtual; procedure CustomSort(Compare: TWStringListSortCompare); virtual; property Duplicates: TDuplicates read FDuplicates write FDuplicates; property Sorted: Boolean read FSorted write SetSorted; property CaseSensitive: Boolean read FCaseSensitive write SetCaseSensitive; property OnChange: TNotifyEvent read FOnChange write FOnChange; property OnChanging: TNotifyEvent read FOnChanging write FOnChanging; end; TWideStringList = TWStringList; TWideStrings = TWStrings; // WideChar functions function CharToWideChar(Ch: AnsiChar): WideChar; function WideCharToChar(Ch: WideChar): AnsiChar; // PWideChar functions procedure MoveWideChar(const Source; var Dest; Count: Integer); function StrLenW(const Str: PWideChar): Cardinal; function StrEndW(const Str: PWideChar): PWideChar; function StrMoveW(Dest: PWideChar; const Source: PWideChar; Count: Cardinal): PWideChar; function StrCopyW(Dest: PWideChar; const Source: PWideChar): PWideChar; function StrECopyW(Dest: PWideChar; const Source: PWideChar): PWideChar; function StrLCopyW(Dest: PWideChar; const Source: PWideChar; MaxLen: Cardinal): PWideChar; function StrPCopyWW(Dest: PWideChar; const Source: WideString): PWideChar; function StrPCopyW(Dest: PWideChar; const Source: string): PWideChar; function StrPLCopyWW(Dest: PWideChar; const Source: WideString; MaxLen: Cardinal): PWideChar; function StrPLCopyW(Dest: PWideChar; const Source: string; MaxLen: Cardinal): PWideChar; function StrCatW(Dest: PWideChar; const Source: PWideChar): PWideChar; function StrLCatW(Dest: PWideChar; const Source: PWideChar; MaxLen: Cardinal): PWideChar; function StrCompW(const Str1, Str2: PWideChar): Integer; function StrICompW(const Str1, Str2: PWideChar; MaxLen: Cardinal): Integer; function StrLCompW(const Str1, Str2: PWideChar; MaxLen: Cardinal): Integer; function StrLICompW(const Str1, Str2: PWideChar; MaxLen: Cardinal): Integer; function StrLICompW2(const Str1, Str2: PWideChar; MaxLen: Cardinal): Integer; function StrNScanW(const Str1, Str2: PWideChar): Integer; function StrRNScanW(const Str1, Str2: PWideChar): Integer; function StrScanW(const Str: PWideChar; Ch: WideChar): PWideChar; overload; function StrScanW(Str: PWideChar; Chr: WideChar; StrLen: Cardinal): PWideChar; overload; function StrRScanW(const Str: PWideChar; Chr: WideChar): PWideChar; function StrPosW(const Str, SubStr: PWideChar): PWideChar; function StrAllocW(WideSize: Cardinal): PWideChar; function StrBufSizeW(const Str: PWideChar): Cardinal; function StrNewW(const Str: PWideChar): PWideChar; overload; function StrNewW(const Str: WideString): PWideChar; overload; procedure StrDisposeW(Str: PWideChar); procedure StrDisposeAndNilW(var Str: PWideChar); procedure StrSwapByteOrder(Str: PWideChar); // WideString functions function WidePos(const SubStr, S: WideString): Integer; function WideQuotedStr(const S: WideString; Quote: WideChar): WideString; function WideExtractQuotedStr(var Src: PWideChar; Quote: WideChar): WideString; {$IFNDEF RTL140_UP} function WideCompareText(const S1, S2: WideString): Integer; function WideCompareStr(const S1, S2: WideString): Integer; function WideUpperCase(const S: WideString): WideString; function WideLowerCase(const S: WideString): WideString; {$ENDIF ~RTL140_UP} function TrimW(const S: WideString): WideString; function TrimLeftW(const S: WideString): WideString; function TrimRightW(const S: WideString): WideString; function TrimLeftLengthW(const S: WideString): Integer; function TrimRightLengthW(const S: WideString): Integer; implementation uses {$IFDEF HAS_UNIT_RTLCONSTS} RTLConsts, {$ELSE} Consts, {$ENDIF HAS_UNIT_RTLCONSTS} {$IFDEF MSWINDOWS} Windows, {$ENDIF MSWINDOWS} Math; procedure SwapWordByteOrder(P: PChar; Len: Cardinal); var B: Char; begin while Len > 0 do begin B := P[0]; P[0] := P[1]; P[1] := B; Inc(P, 2); Dec(Len); end; end; //=== WideChar functions ===================================================== function CharToWideChar(Ch: Char): WideChar; var WS: WideString; begin WS := Ch; Result := WS[1]; end; function WideCharToChar(Ch: WideChar): AnsiChar; var S: AnsiString; begin S := Ch; Result := S[1]; end; //=== PWideChar functions ==================================================== procedure MoveWideChar(const Source; var Dest; Count: Integer); begin Move(Source, Dest, Count * SizeOf(WideChar)); end; function StrAllocW(WideSize: Cardinal): PWideChar; begin WideSize := SizeOf(WideChar) * WideSize + SizeOf(Cardinal); Result := AllocMem(WideSize); Cardinal(Pointer(Result)^) := WideSize; Inc(Result, SizeOf(Cardinal) div SizeOf(WideChar)); end; function StrNewW(const Str: PWideChar): PWideChar; // Duplicates the given string (if not nil) and returns the address of the new string. var Size: Cardinal; begin if Str = nil then Result := nil else begin Size := StrLenW(Str) + 1; Result := StrMoveW(StrAllocW(Size), Str, Size); end; end; function StrNewW(const Str: WideString): PWideChar; begin Result := StrNewW(PWideChar(Str)); end; procedure StrDisposeW(Str: PWideChar); // releases a string allocated with StrNewW or StrAllocW begin if Str <> nil then begin Dec(Str, SizeOf(Cardinal) div SizeOf(WideChar)); FreeMem(Str); end; end; procedure StrDisposeAndNilW(var Str: PWideChar); begin StrDisposeW(Str); Str := nil; end; function StrLICompW(const Str1, Str2: PWideChar; MaxLen: Cardinal): Integer; var P1, P2: WideString; begin SetString(P1, Str1, Min(MaxLen, StrLenW(Str1))); SetString(P2, Str2, Min(MaxLen, StrLenW(Str2))); Result := WideCompareText(P1, P2); end; function StrLICompW2(const Str1, Str2: PWideChar; MaxLen: Cardinal): Integer; var P1, P2: WideString; begin // faster than the JclUnicode.StrLICompW function SetString(P1, Str1, Min(MaxLen, StrLenW(Str1))); SetString(P2, Str2, Min(MaxLen, StrLenW(Str2))); Result := WideCompareText(P1, P2); end; function StrCompW(const Str1, Str2: PWideChar): Integer; var NullWide: WideChar; SA, SB: PWideChar; begin Result := 0; if Str1 = Str2 then // "equal" and "nil" case Exit; NullWide := #0; if Str1 = nil then SA := @NullWide else SA := Str1; if Str2 = nil then SB := @NullWide else SB := Str2; while (SA^ = SB^) and (SA^ <> #0) and (SB^ <> #0) do begin Inc(SA); Inc(SB); end; Result := Integer(SA^) - Integer(SB^); end; function StrLCompW(const Str1, Str2: PWideChar; MaxLen: Cardinal): Integer; var NullWide: WideChar; SA, SB: PWideChar; begin Result := 0; if Str1 = Str2 then // "equal" and "nil" case Exit; NullWide := #0; if Str1 = nil then SA := @NullWide else SA := Str1; if Str2 = nil then SB := @NullWide else SB := Str2; while (MaxLen > 0) and (SA^ = SB^) and (SA^ <> #0) and (SB^ <> #0) do begin Inc(SA); Inc(SB); Dec(MaxLen); end; if MaxLen > 0 then Result := Integer(SA^) - Integer(SB^) else Result := 0; end; function StrICompW(const Str1, Str2: PWideChar; MaxLen: Cardinal): Integer; begin Result := StrLICompW(Str1, Str2, Max(StrLenW(Str1), StrLenW(Str2))); end; function StrPosW(const Str, SubStr: PWideChar): PWideChar; var P: PWideChar; I: Integer; begin Result := nil; if (Str = nil) or (SubStr = nil) or (Str^ = #0) or (SubStr^ = #0) then Exit; Result := Str; while Result^ <> #0 do begin if Result^ <> SubStr^ then Inc(Result) else begin P := Result + 1; I := 1; while (P^ <> #0) and (P^ = SubStr[I]) do begin Inc(I); Inc(P); end; if SubStr[I] = #0 then Exit else Inc(Result); end; end; Result := nil; end; function StrLenW(const Str: PWideChar): Cardinal; begin Result := 0; if Str <> nil then while Str[Result] <> #0 do Inc(Result); end; function StrScanW(const Str: PWideChar; Ch: WideChar): PWideChar; begin Result := Str; if Result <> nil then begin while (Result^ <> #0) and (Result^ <> Ch) do Inc(Result); if (Result^ = #0) and (Ch <> #0) then Result := nil; end; end; function StrEndW(const Str: PWideChar): PWideChar; begin Result := Str; if Result <> nil then while Result^ <> #0 do Inc(Result); end; function StrCopyW(Dest: PWideChar; const Source: PWideChar): PWideChar; var Src: PWideChar; begin Result := Dest; if Dest <> nil then begin Src := Source; if Src <> nil then while Src^ <> #0 do begin Dest^ := Src^; Inc(Src); Inc(Dest); end; Dest^ := #0; end; end; function StrECopyW(Dest: PWideChar; const Source: PWideChar): PWideChar; var Src: PWideChar; begin if Dest <> nil then begin Src := Source; if Src <> nil then while Src^ <> #0 do begin Dest^ := Src^; Inc(Src); Inc(Dest); end; Dest^ := #0; end; Result := Dest; end; function StrLCopyW(Dest: PWideChar; const Source: PWideChar; MaxLen: Cardinal): PWideChar; var Src: PWideChar; begin Result := Dest; if (Dest <> nil) and (MaxLen > 0) then begin Src := Source; if Src <> nil then while (MaxLen > 0) and (Src^ <> #0) do begin Dest^ := Src^; Inc(Src); Inc(Dest); Dec(MaxLen); end; Dest^ := #0; end; end; function StrCatW(Dest: PWideChar; const Source: PWideChar): PWideChar; begin Result := Dest; StrCopyW(StrEndW(Dest), Source); end; function StrLCatW(Dest: PWideChar; const Source: PWideChar; MaxLen: Cardinal): PWideChar; begin Result := Dest; StrLCopyW(StrEndW(Dest), Source, MaxLen); end; function StrMoveW(Dest: PWideChar; const Source: PWideChar; Count: Cardinal): PWideChar; begin Result := Dest; if Count > 0 then Move(Source^, Dest^, Integer(Count) * SizeOf(WideChar)); end; function StrPCopyWW(Dest: PWideChar; const Source: WideString): PWideChar; begin Result := StrLCopyW(Dest, PWideChar(Source), Length(Source)); end; function StrPLCopyWW(Dest: PWideChar; const Source: WideString; MaxLen: Cardinal): PWideChar; begin Result := StrLCopyW(Dest, PWideChar(Source), MaxLen); end; function StrRScanW(const Str: PWideChar; Chr: WideChar): PWideChar; var P: PWideChar; begin Result := nil; if Str <> nil then begin P := Str; repeat if P^ = Chr then Result := P; Inc(P); until P^ = #0; end; end; // (rom) following functions copied from JclUnicode.pas // exchanges in each character of the given string the low order and high order // byte to go from LSB to MSB and vice versa. // EAX contains address of string procedure StrSwapByteOrder(Str: PWideChar); asm PUSH ESI PUSH EDI MOV ESI, EAX MOV EDI, ESI XOR EAX, EAX // clear high order byte to be able to use 32bit operand below @@1: LODSW OR EAX, EAX JZ @@2 XCHG AL, AH STOSW JMP @@1 @@2: POP EDI POP ESI end; function StrNScanW(const Str1, Str2: PWideChar): Integer; // Determines where (in Str1) the first time one of the characters of Str2 appear. // The result is the length of a string part of Str1 where none of the characters of // Str2 do appear (not counting the trailing #0 and starting with position 0 in Str1). var Run: PWideChar; begin Result := -1; if (Str1 <> nil) and (Str2 <> nil) then begin Run := Str1; while Run^ <> #0 do begin if StrScanW(Str2, Run^) <> nil then Break; Inc(Run); end; Result := Run - Str1; end; end; function StrRNScanW(const Str1, Str2: PWideChar): Integer; // This function does the same as StrRNScanW but uses Str1 in reverse order. This // means Str1 points to the last character of a string, is traversed reversely // and terminates with a starting #0. This is useful for parsing strings stored // in reversed macro buffers etc. var Run: PWideChar; begin Result := -1; if (Str1 <> nil) and (Str2 <> nil) then begin Run := Str1; while Run^ <> #0 do begin if StrScanW(Str2, Run^) <> nil then Break; Dec(Run); end; Result := Str1 - Run; end; end; // Returns a pointer to first occurrence of a specified character in a string // or nil if not found. // Note: this is just a binary search for the specified character and there's no // check for a terminating null. Instead at most StrLen characters are // searched. This makes this function extremly fast. // // on enter EAX contains Str, EDX contains Chr and ECX StrLen // on exit EAX contains result pointer or nil function StrScanW(Str: PWideChar; Chr: WideChar; StrLen: Cardinal): PWideChar; asm TEST EAX, EAX JZ @@Exit // get out if the string is nil or StrLen is 0 JCXZ @@Exit @@Loop: CMP [EAX], DX // this unrolled loop is actually faster on modern processors JE @@Exit // than REP SCASW ADD EAX, 2 DEC ECX JNZ @@Loop XOR EAX, EAX @@Exit: end; function StrBufSizeW(const Str: PWideChar): Cardinal; // Returns max number of wide characters that can be stored in a buffer // allocated by StrAllocW. var P: PWideChar; begin if Str <> nil then begin P := Str; Dec(P, SizeOf(Cardinal) div SizeOf(WideChar)); Result := (Cardinal(PInteger(P)^) - SizeOf(Cardinal)) div SizeOf(WideChar); end else Result := 0; end; function StrPCopyW(Dest: PWideChar; const Source: string): PWideChar; // copies a Pascal-style string to a null-terminated wide string begin Result := StrPLCopyW(Dest, Source, Cardinal(Length(Source))); Result[Length(Source)] := WideNull; end; function StrPLCopyW(Dest: PWideChar; const Source: string; MaxLen: Cardinal): PWideChar; // copies characters from a Pascal-style string into a null-terminated wide string asm PUSH EDI PUSH ESI MOV EDI, EAX MOV ESI, EDX MOV EDX, EAX XOR AX, AX @@1: LODSB STOSW DEC ECX JNZ @@1 MOV EAX, EDX POP ESI POP EDI end; //=== WideString functions =================================================== function WidePos(const SubStr, S: WideString): Integer; var P: PWideChar; begin P := StrPosW(PWideChar(S), PWideChar(SubStr)); if P <> nil then Result := P - PWideChar(S) + 1 else Result := 0; end; // original code by Mike Lischke (extracted from JclUnicode.pas) function WideQuotedStr(const S: WideString; Quote: WideChar): WideString; var P, Src, Dest: PWideChar; AddCount: Integer; begin AddCount := 0; P := StrScanW(PWideChar(S), Quote); while P <> nil do begin Inc(P); Inc(AddCount); P := StrScanW(P, Quote); end; if AddCount = 0 then Result := Quote + S + Quote else begin SetLength(Result, Length(S) + AddCount + 2); Dest := PWideChar(Result); Dest^ := Quote; Inc(Dest); Src := PWideChar(S); P := StrScanW(Src, Quote); repeat Inc(P); MoveWideChar(Src^, Dest^, P - Src); Inc(Dest, P - Src); Dest^ := Quote; Inc(Dest); Src := P; P := StrScanW(Src, Quote); until P = nil; P := StrEndW(Src); MoveWideChar(Src^, Dest^, P - Src); Inc(Dest, P - Src); Dest^ := Quote; end; end; // original code by Mike Lischke (extracted from JclUnicode.pas) function WideExtractQuotedStr(var Src: PWideChar; Quote: WideChar): WideString; var P, Dest: PWideChar; DropCount: Integer; begin Result := ''; if (Src = nil) or (Src^ <> Quote) then Exit; Inc(Src); DropCount := 1; P := Src; Src := StrScanW(Src, Quote); while Src <> nil do // count adjacent pairs of quote chars begin Inc(Src); if Src^ <> Quote then Break; Inc(Src); Inc(DropCount); Src := StrScanW(Src, Quote); end; if Src = nil then Src := StrEndW(P); if (Src - P) <= 1 then Exit; if DropCount = 1 then SetString(Result, P, Src - P - 1) else begin SetLength(Result, Src - P - DropCount); Dest := PWideChar(Result); Src := StrScanW(P, Quote); while Src <> nil do begin Inc(Src); if Src^ <> Quote then Break; MoveWideChar(P^, Dest^, Src - P); Inc(Dest, Src - P); Inc(Src); P := Src; Src := StrScanW(Src, Quote); end; if Src = nil then Src := StrEndW(P); MoveWideChar(P^, Dest^, Src - P - 1); end; end; function TrimW(const S: WideString): WideString; // available from Delphi 7 up {$IFDEF RTL150_UP} begin Result := Trim(S); end; {$ELSE ~RTL150_UP} var I, L: Integer; begin L := Length(S); I := 1; while (I <= L) and (S[I] <= ' ') do Inc(I); if I > L then Result := '' else begin while S[L] <= ' ' do Dec(L); Result := Copy(S, I, L - I + 1); end; end; {$ENDIF ~RTL150_UP} function TrimLeftW(const S: WideString): WideString; // available from Delphi 7 up {$IFDEF RTL150_UP} begin Result := TrimLeft(S); end; {$ELSE ~RTL150_UP} var I, L: Integer; begin L := Length(S); I := 1; while (I <= L) and (S[I] <= ' ') do Inc(I); Result := Copy(S, I, Maxint); end; {$ENDIF ~RTL150_UP} function TrimRightW(const S: WideString): WideString; // available from Delphi 7 up {$IFDEF RTL150_UP} begin Result := TrimRight(S); end; {$ELSE ~RTL150_UP} var I: Integer; begin I := Length(S); while (I > 0) and (S[I] <= ' ') do Dec(I); Result := Copy(S, 1, I); end; {$ENDIF ~RTL150_UP} // functions missing in Delphi 5 / FPC {$IFNDEF RTL140_UP} function WideCompareText(const S1, S2: WideString): Integer; begin {$IFDEF MSWINDOWS} if Win32Platform = VER_PLATFORM_WIN32_WINDOWS then Result := AnsiCompareText(string(S1), string(S2)) else Result := CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE, PWideChar(S1), Length(S1), PWideChar(S2), Length(S2)) - 2; {$ELSE ~MSWINDOWS} { TODO : Don't cheat here } Result := CompareText(S1, S2); {$ENDIF MSWINDOWS} end; function WideCompareStr(const S1, S2: WideString): Integer; begin {$IFDEF MSWINDOWS} if Win32Platform = VER_PLATFORM_WIN32_WINDOWS then Result := AnsiCompareStr(string(S1), string(S2)) else Result := CompareStringW(LOCALE_USER_DEFAULT, 0, PWideChar(S1), Length(S1), PWideChar(S2), Length(S2)) - 2; {$ELSE ~MSWINDOWS} { TODO : Don't cheat here } Result := CompareString(S1, S2); {$ENDIF ~MSWINDOWS} end; function WideUpperCase(const S: WideString): WideString; begin Result := S; if Result <> '' then {$IFDEF MSWINDOWS} CharUpperBuffW(Pointer(Result), Length(Result)); {$ELSE ~MSWINDOWS} { TODO : Don't cheat here } Result := UpperCase(Result); {$ENDIF ~MSWINDOWS} end; function WideLowerCase(const S: WideString): WideString; begin Result := S; if Result <> '' then {$IFDEF MSWINDOWS} CharLowerBuffW(Pointer(Result), Length(Result)); {$ELSE ~MSWINDOWS} { TODO : Don't cheat here } Result := LowerCase(Result); {$ENDIF ~MSWINDOWS} end; {$ENDIF ~RTL140_UP} function TrimLeftLengthW(const S: WideString): Integer; var Len: Integer; begin Len := Length(S); Result := 1; while (Result <= Len) and (S[Result] <= #32) do Inc(Result); Result := Len - Result + 1; end; function TrimRightLengthW(const S: WideString): Integer; begin Result := Length(S); while (Result > 0) and (S[Result] <= #32) do Dec(Result); end; //=== { TWStrings } ========================================================== constructor TWStrings.Create; begin inherited Create; // FLineSeparator := WideChar($2028); {$IFDEF MSWINDOWS} FLineSeparator := WideChar(13) + '' + WideChar(10); // compiler wants it this way {$ENDIF MSWINDOWS} {$IFDEF UNIX} FLineSeparator := WideChar(10); {$ENDIF UNIX} FNameValueSeparator := '='; FDelimiter := ','; FQuoteChar := '"'; end; function TWStrings.Add(const S: WideString): Integer; begin Result := AddObject(S, nil); end; function TWStrings.AddObject(const S: WideString; AObject: TObject): Integer; begin Result := Count; InsertObject(Result, S, AObject); end; procedure TWStrings.AddStrings(Strings: TWStrings); var I: Integer; begin for I := 0 to Strings.Count - 1 do AddObject(Strings.GetP(I)^, Strings.Objects[I]); end; procedure TWStrings.AddStrings(Strings: TStrings); var I: Integer; begin for I := 0 to Strings.Count - 1 do AddObject(Strings.Strings[I], Strings.Objects[I]); end; procedure TWStrings.AddStringsTo(Dest: TStrings); var I: Integer; begin for I := 0 to Count - 1 do Dest.AddObject(GetP(I)^, Objects[I]); end; procedure TWStrings.Append(const S: WideString); begin Add(S); end; procedure TWStrings.Assign(Source: TPersistent); begin if Source is TWStrings then begin BeginUpdate; try Clear; FDelimiter := TWStrings(Source).FDelimiter; FNameValueSeparator := TWStrings(Source).FNameValueSeparator; FQuoteChar := TWStrings(Source).FQuoteChar; AddStrings(TWStrings(Source)); finally EndUpdate; end; end else if Source is TStrings then begin BeginUpdate; try Clear; {$IFDEF RTL150_UP} FNameValueSeparator := CharToWideChar(TStrings(Source).NameValueSeparator); {$ENDIF RTL150_UP} {$IFDEF RTL140_UP} FQuoteChar := CharToWideChar(TStrings(Source).QuoteChar); FDelimiter := CharToWideChar(TStrings(Source).Delimiter); {$ENDIF RTL140_UP} AddStrings(TStrings(Source)); finally EndUpdate; end; end else inherited Assign(Source); end; procedure TWStrings.AssignTo(Dest: TPersistent); var I: Integer; begin if Dest is TStrings then begin TStrings(Dest).BeginUpdate; try TStrings(Dest).Clear; {$IFDEF RTL150_UP} TStrings(Dest).NameValueSeparator := WideCharToChar(NameValueSeparator); {$ENDIF RTL150_UP} {$IFDEF RTL140_UP} TStrings(Dest).QuoteChar := WideCharToChar(QuoteChar); TStrings(Dest).Delimiter := WideCharToChar(Delimiter); {$ENDIF RTL140_UP} for I := 0 to Count - 1 do TStrings(Dest).AddObject(GetP(I)^, Objects[I]); finally TStrings(Dest).EndUpdate; end; end else inherited AssignTo(Dest); end; procedure TWStrings.BeginUpdate; begin if FUpdateCount = 0 then SetUpdateState(True); Inc(FUpdateCount); end; function TWStrings.CompareStrings(const S1, S2: WideString): Integer; begin Result := WideCompareText(S1, S2); end; function TWStrings.CreateAnsiStringList: TStrings; var I: Integer; begin Result := TStringList.Create; try Result.BeginUpdate; for I := 0 to Count - 1 do Result.AddObject(GetP(I)^, Objects[I]); Result.EndUpdate; except Result.Free; raise; end; end; procedure TWStrings.DefineProperties(Filer: TFiler); function DoWrite: Boolean; begin if Filer.Ancestor <> nil then begin Result := True; if Filer.Ancestor is TWStrings then Result := not Equals(TWStrings(Filer.Ancestor)) end else Result := Count > 0; end; begin Filer.DefineProperty('Strings', ReadData, WriteData, DoWrite); end; procedure TWStrings.EndUpdate; begin Dec(FUpdateCount); if FUpdateCount = 0 then SetUpdateState(False); end; function TWStrings.Equals(Strings: TStrings): Boolean; var I: Integer; begin Result := False; if Strings.Count = Count then begin for I := 0 to Count - 1 do if Strings[I] <> PStrings[I]^ then Exit; Result := True; end; end; function TWStrings.Equals(Strings: TWStrings): Boolean; var I: Integer; begin Result := False; if Strings.Count = Count then begin for I := 0 to Count - 1 do if Strings[I] <> PStrings[I]^ then Exit; Result := True; end; end; procedure TWStrings.Exchange(Index1, Index2: Integer); var TempObject: TObject; TempString: WideString; begin BeginUpdate; try TempString := PStrings[Index1]^; TempObject := Objects[Index1]; PStrings[Index1]^ := PStrings[Index2]^; Objects[Index1] := Objects[Index2]; PStrings[Index2]^ := TempString; Objects[Index2] := TempObject; finally EndUpdate; end; end; function TWStrings.ExtractName(const S: WideString): WideString; var Index: Integer; begin Result := S; Index := WidePos(NameValueSeparator, Result); if Index <> 0 then SetLength(Result, Index - 1) else SetLength(Result, 0); end; function TWStrings.Get(Index: Integer): WideString; begin Result := GetP(Index)^; end; function TWStrings.GetCapacity: Integer; begin Result := Count; end; function TWStrings.GetCommaText: WideString; begin Result := GetDelimitedTextEx(',', '"'); end; function TWStrings.GetDelimitedText: WideString; begin Result := GetDelimitedTextEx(FDelimiter, FQuoteChar); end; function TWStrings.GetDelimitedTextEx(ADelimiter, AQuoteChar: WideChar): WideString; var S: WideString; P: PWideChar; I, Num: Integer; begin Num := GetCount; if (Num = 1) and (GetP(0)^ = '') then Result := AQuoteChar + '' + AQuoteChar // Compiler wants it this way else begin Result := ''; for I := 0 to Count - 1 do begin S := GetP(I)^; P := PWideChar(S); while True do begin case P[0] of WideChar(0)..WideChar(32): Inc(P); else if (P[0] = AQuoteChar) or (P[0] = ADelimiter) then Inc(P) else Break; end; end; if P[0] <> WideChar(0) then S := WideQuotedStr(S, AQuoteChar); Result := Result + S + ADelimiter; end; System.Delete(Result, Length(Result), 1); end; end; function TWStrings.GetName(Index: Integer): WideString; var I: Integer; begin Result := GetP(Index)^; I := WidePos(FNameValueSeparator, Result); if I > 0 then SetLength(Result, I - 1); end; function TWStrings.GetObject(Index: Integer): TObject; begin Result := nil; end; function TWStrings.GetText: PWideChar; begin Result := StrNewW(GetTextStr); end; function TWStrings.GetTextStr: WideString; var I: Integer; Len, LL: Integer; P: PWideChar; W: PWideString; begin Len := 0; LL := Length(LineSeparator); for I := 0 to Count - 1 do Inc(Len, Length(GetP(I)^) + LL); SetLength(Result, Len); P := PWideChar(Result); for I := 0 to Count - 1 do begin W := GetP(I); Len := Length(W^); if Len > 0 then begin MoveWideChar(W^[1], P[0], Len); Inc(P, Len); end; if LL > 0 then begin MoveWideChar(FLineSeparator[1], P[0], LL); Inc(P, LL); end; end; end; function TWStrings.GetValue(const Name: WideString): WideString; var Idx: Integer; begin Idx := IndexOfName(Name); if Idx >= 0 then Result := GetValueFromIndex(Idx) else Result := ''; end; function TWStrings.GetValueFromIndex(Index: Integer): WideString; var I: Integer; begin Result := GetP(Index)^; I := WidePos(FNameValueSeparator, Result); if I > 0 then System.Delete(Result, 1, I) else Result := ''; end; function TWStrings.IndexOf(const S: WideString): Integer; begin for Result := 0 to Count - 1 do if CompareStrings(GetP(Result)^, S) = 0 then Exit; Result := -1; end; function TWStrings.IndexOfName(const Name: WideString): Integer; begin for Result := 0 to Count - 1 do if CompareStrings(Names[Result], Name) = 0 then Exit; Result := -1; end; function TWStrings.IndexOfObject(AObject: TObject): Integer; begin for Result := 0 to Count - 1 do if Objects[Result] = AObject then Exit; Result := -1; end; procedure TWStrings.Insert(Index: Integer; const S: WideString); begin InsertObject(Index, S, nil); end; procedure TWStrings.InsertObject(Index: Integer; const S: WideString; AObject: TObject); begin end; procedure TWStrings.LoadFromFile(const FileName: AnsiString; WideFileOptions: TWideFileOptions = []); var Stream: TFileStream; begin Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); try LoadFromStream(Stream, WideFileOptions); finally Stream.Free; end; end; procedure TWStrings.LoadFromStream(Stream: TStream; WideFileOptions: TWideFileOptions = []); var AnsiS: AnsiString; WideS: WideString; WC: WideChar; begin BeginUpdate; try Clear; if foAnsiFile in WideFileOptions then begin Stream.Read(WC, SizeOf(WC)); Stream.Seek(-SizeOf(WC), soFromCurrent); if (Hi(Word(WC)) <> 0) and (WC <> BOM_LSB_FIRST) and (WC <> BOM_MSB_FIRST) then begin SetLength(AnsiS, Stream.Size - Stream.Position); Stream.Read(AnsiS[1], Length(AnsiS)); SetTextStr(AnsiS); Exit; end; end; Stream.Read(WC, SizeOf(WC)); if (WC <> BOM_LSB_FIRST) and (WC <> BOM_MSB_FIRST) then Stream.Seek(-SizeOf(WC), soFromCurrent); SetLength(WideS, Stream.Size - Stream.Position); Stream.Read(WideS[1], Length(WideS) * SizeOf(WideChar)); if WC = BOM_MSB_FIRST then SwapWordByteOrder(Pointer(WideS), Length(WideS)); SetTextStr(WideS); finally EndUpdate; end; end; procedure TWStrings.Move(CurIndex, NewIndex: Integer); var TempObject: TObject; TempString: WideString; begin if CurIndex <> NewIndex then begin BeginUpdate; try TempString := GetP(CurIndex)^; TempObject := GetObject(CurIndex); Delete(CurIndex); InsertObject(NewIndex, TempString, TempObject); finally EndUpdate; end; end; end; procedure TWStrings.ReadData(Reader: TReader); begin BeginUpdate; try Clear; Reader.ReadListBegin; while not Reader.EndOfList do if Reader.NextValue in [vaLString, vaString] then Add(Reader.ReadString) else Add(Reader.ReadWideString); Reader.ReadListEnd; finally EndUpdate; end; end; procedure TWStrings.SaveToFile(const FileName: AnsiString; WideFileOptions: TWideFileOptions = []); var Stream: TFileStream; begin Stream := TFileStream.Create(FileName, fmCreate); try SaveToStream(Stream, WideFileOptions); finally Stream.Free; end; end; procedure TWStrings.SaveToStream(Stream: TStream; WideFileOptions: TWideFileOptions = []); var AnsiS: AnsiString; WideS: WideString; WC: WideChar; begin if foAnsiFile in WideFileOptions then begin AnsiS := GetTextStr; Stream.Write(AnsiS[1], Length(AnsiS)); end else begin if foUnicodeLB in WideFileOptions then begin WC := BOM_LSB_FIRST; Stream.Write(WC, SizeOf(WC)); end; WideS := GetTextStr; Stream.Write(WideS[1], Length(WideS) * SizeOf(WideChar)); end; end; procedure TWStrings.SetCapacity(NewCapacity: Integer); begin end; procedure TWStrings.SetCommaText(const Value: WideString); begin SetDelimitedTextEx(',', '"', Value); end; procedure TWStrings.SetDelimitedText(const Value: WideString); begin SetDelimitedTextEx(Delimiter, QuoteChar, Value); end; procedure TWStrings.SetDelimitedTextEx(ADelimiter, AQuoteChar: WideChar; const Value: WideString); var P, P1: PWideChar; S: WideString; procedure IgnoreWhiteSpace(var P: PWideChar); begin while True do case P^ of WideChar(1)..WideChar(32): Inc(P); else Break; end; end; begin BeginUpdate; try Clear; P := PWideChar(Value); IgnoreWhiteSpace(P); while P[0] <> WideChar(0) do begin if P[0] = AQuoteChar then S := WideExtractQuotedStr(P, AQuoteChar) else begin P1 := P; while (P[0] > WideChar(32)) and (P[0] <> ADelimiter) do Inc(P); SetString(S, P1, P - P1); end; Add(S); IgnoreWhiteSpace(P); if P[0] = ADelimiter then begin Inc(P); IgnoreWhiteSpace(P); end; end; finally EndUpdate; end; end; procedure TWStrings.SetText(Text: PWideChar); begin SetTextStr(Text); end; procedure TWStrings.SetTextStr(const Value: WideString); var P, Start: PWideChar; S: WideString; Len: Integer; begin BeginUpdate; try Clear; if Value <> '' then begin P := PWideChar(Value); if P <> nil then begin while P[0] <> WideChar(0) do begin Start := P; while True do begin case P[0] of WideChar(0), WideChar(10), WideChar(13): Break; end; Inc(P); end; Len := P - Start; if Len > 0 then begin SetString(S, Start, Len); AddObject(S, nil); // consumes most time end else AddObject('', nil); if P[0] = WideChar(13) then Inc(P); if P[0] = WideChar(10) then Inc(P); end; end; end; finally EndUpdate; end; end; procedure TWStrings.SetUpdateState(Updating: Boolean); begin end; procedure TWStrings.SetValue(const Name, Value: WideString); var Idx: Integer; begin Idx := IndexOfName(Name); if Idx >= 0 then SetValueFromIndex(Idx, Value) else if Value <> '' then Add(Name + NameValueSeparator + Value); end; procedure TWStrings.SetValueFromIndex(Index: Integer; const Value: WideString); var S: WideString; I: Integer; begin if Value = '' then Delete(Index) else begin if Index < 0 then Index := Add(''); S := GetP(Index)^; I := WidePos(NameValueSeparator, S); if I > 0 then System.Delete(S, I, MaxInt); S := S + NameValueSeparator + Value; Put(Index, S); end; end; procedure TWStrings.WriteData(Writer: TWriter); var I: Integer; begin Writer.WriteListBegin; for I := 0 to Count - 1 do Writer.WriteWideString(GetP(I)^); Writer.WriteListEnd; end; //=== { TWStringList } ======================================================= constructor TWStringList.Create; begin inherited Create; FList := TList.Create; end; destructor TWStringList.Destroy; begin FOnChange := nil; FOnChanging := nil; Inc(FUpdateCount); // do not call unnecessary functions Clear; FList.Free; inherited Destroy; end; function TWStringList.AddObject(const S: WideString; AObject: TObject): Integer; begin if not Sorted then Result := Count else if Find(S, Result) then case Duplicates of dupIgnore: Exit; dupError: raise EListError.CreateRes(@SDuplicateString); end; InsertObject(Result, S, AObject); end; procedure TWStringList.Changed; begin if Assigned(FOnChange) then FOnChange(Self); end; procedure TWStringList.Changing; begin if Assigned(FOnChanging) then FOnChanging(Self); end; procedure TWStringList.Clear; var I: Integer; Item: PWStringItem; begin if FUpdateCount = 0 then Changing; for I := 0 to Count - 1 do begin Item := PWStringItem(FList[I]); Item.FString := ''; FreeMem(Item); end; FList.Clear; if FUpdateCount = 0 then Changed; end; function TWStringList.CompareStrings(const S1, S2: WideString): Integer; begin if CaseSensitive then Result := WideCompareStr(S1, S2) else Result := WideCompareText(S1, S2); end; threadvar CustomSortList: TWStringList; CustomSortCompare: TWStringListSortCompare; function WStringListCustomSort(Item1, Item2: Pointer): Integer; begin Result := CustomSortCompare(CustomSortList, CustomSortList.FList.IndexOf(Item1), CustomSortList.FList.IndexOf(Item2)); end; procedure TWStringList.CustomSort(Compare: TWStringListSortCompare); var TempList: TWStringList; TempCompare: TWStringListSortCompare; begin TempList := CustomSortList; TempCompare := CustomSortCompare; CustomSortList := Self; CustomSortCompare := Compare; try Changing; FList.Sort(WStringListCustomSort); Changed; finally CustomSortList := TempList; CustomSortCompare := TempCompare; end; end; procedure TWStringList.Delete(Index: Integer); var Item: PWStringItem; begin if FUpdateCount = 0 then Changing; Item := PWStringItem(FList[Index]); FList.Delete(Index); Item.FString := ''; FreeMem(Item); if FUpdateCount = 0 then Changed; end; procedure TWStringList.Exchange(Index1, Index2: Integer); begin if FUpdateCount = 0 then Changing; FList.Exchange(Index1, Index2); if FUpdateCount = 0 then Changed; end; function TWStringList.Find(const S: WideString; var Index: Integer): Boolean; var L, H, I, C: Integer; begin Result := False; if Sorted then begin L := 0; H := Count - 1; while L <= H do begin I := (L + H) shr 1; C := CompareStrings(GetItem(I).FString, S); if C < 0 then L := I + 1 else begin H := I - 1; if C = 0 then begin Result := True; if Duplicates <> dupAccept then L := I; end; end; end; Index := L; end else begin Index := IndexOf(S); Result := Index <> -1; end; end; function TWStringList.GetCapacity: Integer; begin Result := FList.Capacity; end; function TWStringList.GetCount: Integer; begin Result := FList.Count; end; function TWStringList.GetItem(Index: Integer): PWStringItem; begin Result := FList[Index]; end; function TWStringList.GetObject(Index: Integer): TObject; begin Result := GetItem(Index).FObject; end; function TWStringList.GetP(Index: Integer): PWideString; begin Result := Addr(GetItem(Index).FString); end; function TWStringList.IndexOf(const S: WideString): Integer; begin if Sorted then begin if not Find(S, Result) then Result := -1; end else begin for Result := 0 to Count - 1 do if CompareStrings(GetItem(Result).FString, S) = 0 then Exit; Result := -1; end; end; procedure TWStringList.InsertObject(Index: Integer; const S: WideString; AObject: TObject); var P: PWStringItem; begin if FUpdateCount = 0 then Changing; FList.Insert(Index, nil); // error check P := AllocMem(SizeOf(TWStringItem)); FList[Index] := P; Put(Index, S); if AObject <> nil then PutObject(Index, AObject); if FUpdateCount = 0 then Changed; end; procedure TWStringList.Put(Index: Integer; const Value: WideString); begin if FUpdateCount = 0 then Changing; GetItem(Index).FString := Value; if FUpdateCount = 0 then Changed; end; procedure TWStringList.PutObject(Index: Integer; AObject: TObject); begin if FUpdateCount = 0 then Changing; GetItem(Index).FObject := AObject; if FUpdateCount = 0 then Changed; end; procedure TWStringList.SetCapacity(NewCapacity: Integer); begin FList.Capacity := NewCapacity; end; procedure TWStringList.SetCaseSensitive(const Value: Boolean); begin if Value <> FCaseSensitive then begin FCaseSensitive := Value; if Sorted then begin Sorted := False; Sorted := True; // re-sort end; end; end; procedure TWStringList.SetSorted(Value: Boolean); begin if Value <> FSorted then begin FSorted := Value; if FSorted then begin FSorted := False; Sort; FSorted := True; end; end; end; procedure TWStringList.SetUpdateState(Updating: Boolean); begin if Updating then Changing else Changed; end; function DefaultSort(List: TWStringList; Index1, Index2: Integer): Integer; begin Result := List.CompareStrings(List.GetItem(Index1).FString, List.GetItem(Index2).FString); end; procedure TWStringList.Sort; begin if not Sorted then CustomSort(DefaultSort); end; // History: // $Log: JclWideStrings.pas,v $ // Revision 1.23 2005/10/27 06:54:20 marquardt // removed unneeded Sign function and fixed multiple history entries // // Revision 1.22 2005/10/26 09:15:13 marquardt // most functions now have the same const parameters as their Ansi counterparts // // Revision 1.21 2005/10/26 08:36:29 marquardt // StrPCopyWW and StrPLCopyWW introduced to solve overloaded problem // // Revision 1.20 2005/10/25 16:27:36 marquardt // StrPCopyW and StrPLCopyW overloaded versions deactivated because of Delphi5 compiler problems // // Revision 1.19 2005/10/25 10:33:40 marquardt // made StrPCopyW and StrPLCopyW compatible with the original Unicode.pas by adding overloaded versions // // Revision 1.18 2005/10/25 09:46:35 marquardt // fixes for StrAllocW family and cleaned up Str*W parameter names // // Revision 1.17 2005/10/25 08:54:57 marquardt // make a union of the Str*W family of functions in JclUnicode and JclWideStrings // // Revision 1.16 2005/10/16 05:15:38 marquardt // Str*W family now matches completely Delphi Str* family semantics // // Revision 1.15 2005/07/19 23:21:21 outchy // IT 2968: The result StrLCompW was false when MaxLen characters were compared. // // Revision 1.14 2005/04/07 00:41:35 rrossmair // - changed for FPC 1.9.8 // // Revision 1.13 2005/03/19 21:22:25 rrossmair // - fixed typo in changed StrScanW // // Revision 1.12 2005/03/19 02:47:07 rrossmair // - fixed issue #2680 (WideQuotedStr always fails) // - gives credit to Mike Lischke in header now // // Revision 1.11 2005/03/08 08:33:18 marquardt // overhaul of exceptions and resourcestrings, minor style cleaning // // Revision 1.10 2005/03/01 15:37:40 marquardt // addressing Mantis 0714, 0716, 0720, 0731, 0740 partly or completely // // Revision 1.9 2005/02/24 16:34:40 marquardt // remove divider lines, add section lines (unfinished) // // Revision 1.8 2005/02/14 00:47:23 rrossmair // - removed (redundant) comment in German language. // // Revision 1.7 2004/10/25 15:12:30 marquardt // fix internal error // // Revision 1.6 2004/10/17 21:49:03 rrossmair // added CVS Log entries // // Revision 1.5 rossmair // fixed D6, FPC compatibility // // Revision 1.4 marquardt // complete and fix PWideChar Str functions // // Revision 1.3 marquardt // PH cleaning of JclStrings // // Revision 1.2 rrossmair // replaced some conditional compilation symbols by more appropriate ones // end.