2004-12-28 15:35:31 +01:00
|
|
|
{** Provides various string-related functions.
|
|
|
|
*
|
|
|
|
* Last changed: $Date$ <br />
|
|
|
|
* Revision: $Rev$ <br />
|
|
|
|
* Author: $Author$ <br />
|
|
|
|
*}
|
2004-06-07 17:31:14 +02:00
|
|
|
unit X2UtStrings;
|
|
|
|
|
|
|
|
interface
|
2007-06-08 16:10:03 +02:00
|
|
|
uses
|
|
|
|
Types;
|
2004-12-28 15:35:31 +01:00
|
|
|
|
2007-06-08 16:10:03 +02:00
|
|
|
type
|
|
|
|
{** Backwards compatibility }
|
|
|
|
TSplitArray = TStringDynArray;
|
|
|
|
|
|
|
|
|
2004-12-28 15:35:31 +01:00
|
|
|
{** Formats the specified size.
|
|
|
|
*
|
|
|
|
* @param ABytes the size to format in bytes.
|
|
|
|
* @param AKeepBytes if true, only decimal separators will be added and
|
|
|
|
* the text 'bytes' appended. If False, a suitable unit
|
|
|
|
* will be chosen (KB, MB, GB).
|
2005-11-30 19:17:03 +01:00
|
|
|
* @param AFormat the format used for the output, see the Delphi Help for
|
|
|
|
* FormatFloat.
|
2004-12-28 15:35:31 +01:00
|
|
|
* @result the formatted size.
|
|
|
|
*}
|
2005-11-30 19:17:03 +01:00
|
|
|
function FormatSize(const ABytes: Int64; AKeepBytes: Boolean = False;
|
2005-11-30 19:17:48 +01:00
|
|
|
const AFormat: String = ',0.##'): String;
|
2004-12-28 15:35:31 +01:00
|
|
|
|
|
|
|
{** Compares two strings without case sensitivity.
|
|
|
|
*
|
|
|
|
* @param AMatch the string to match.
|
|
|
|
* @param AAgainst the string to match against.
|
|
|
|
* @param ALength the maximum length to compare.
|
|
|
|
* @result -1 if AMatch is lower by ordinal value than AAgainst,
|
|
|
|
* 0 if the two are equal, 1 if AMatch is higher.
|
|
|
|
*}
|
2004-08-22 17:03:02 +02:00
|
|
|
function CompareTextL(const AMatch, AAgainst: String;
|
|
|
|
const ALength: Integer): Integer;
|
|
|
|
|
2004-12-28 15:35:31 +01:00
|
|
|
{** Compares two strings without case sensitivity.
|
|
|
|
*
|
|
|
|
* @param AMatch the string to match.
|
|
|
|
* @param AAgainst the string to match against.
|
|
|
|
* @param ALength the maximum length to compare.
|
|
|
|
* @result True if the comparison is a match, False otherwise.
|
|
|
|
*}
|
2004-08-22 17:03:02 +02:00
|
|
|
function SameTextL(const AMatch, AAgainst: String;
|
|
|
|
const ALength: Integer): Boolean;
|
|
|
|
|
2004-12-28 15:35:31 +01:00
|
|
|
{** Compares two strings without case sensitivity.
|
|
|
|
*
|
|
|
|
* The length of AAgainst is used as the maximum length to check.
|
|
|
|
*
|
|
|
|
* @param AMatch the string to match
|
|
|
|
* @param AAgainst the string to match against
|
|
|
|
* @result -1 if AMatch is lower by ordinal value than AAgainst,
|
|
|
|
* 0 if the two are equal, 1 if AMatch is higher.
|
|
|
|
*}
|
2004-08-22 17:03:02 +02:00
|
|
|
function CompareTextS(const AMatch, AAgainst: String): Integer;
|
|
|
|
|
2004-12-28 15:35:31 +01:00
|
|
|
{** Compares two strings without case sensitivity.
|
|
|
|
*
|
|
|
|
* The length of AAgainst is used as the maximum length to check.
|
|
|
|
*
|
|
|
|
* @param AMatch the string to match.
|
|
|
|
* @param AAgainst the string to match against.
|
|
|
|
* @result True if the comparison is a match, False otherwise.
|
|
|
|
*}
|
2004-08-22 17:03:02 +02:00
|
|
|
function SameTextS(const AMatch, AAgainst: String): Boolean;
|
|
|
|
|
2004-12-28 15:35:31 +01:00
|
|
|
{** Splits a string on a specified delimiter.
|
|
|
|
*
|
|
|
|
* @param ASource the source string.
|
|
|
|
* @param ADelimiter the delimiter to split on.
|
|
|
|
* @param ADest the array which will receive the split parts.
|
|
|
|
* @todo though optimized, it now fails on #0 characters, need
|
|
|
|
* to determine the end by checking the AnsiString length.
|
|
|
|
*}
|
2014-04-03 16:03:28 +02:00
|
|
|
procedure Split(const ASource, ADelimiter: String; out ADest: TStringDynArray; ASkipEmptyItems: Boolean = False);
|
2004-09-02 16:24:30 +02:00
|
|
|
|
2005-02-11 10:22:38 +01:00
|
|
|
{** Appends string parts with a specified glue value.
|
2004-12-28 15:35:31 +01:00
|
|
|
*
|
2013-10-02 22:38:15 +02:00
|
|
|
* @param ASource the source parts
|
|
|
|
* @param AGlue the string added between the parts
|
|
|
|
* @param ASkipEmptyItems if True, include only items of Length > 0
|
|
|
|
* @result the composed parts
|
2004-12-28 15:35:31 +01:00
|
|
|
*}
|
2013-10-02 22:38:15 +02:00
|
|
|
function Join(ASource: array of string; const AGlue: String; ASkipEmptyItems: Boolean = False): String;
|
2004-10-30 14:28:39 +02:00
|
|
|
|
2005-02-11 10:22:38 +01:00
|
|
|
{** Determines if one path is the child of another path.
|
|
|
|
*
|
|
|
|
* Matches the start of two normalized paths. Either of the path may contain
|
|
|
|
* parent-references (ex. 'some\..\..\path\'). Note that the file system is
|
|
|
|
* not actually accessed, all checks are performed on the strings only.
|
|
|
|
*
|
|
|
|
* @param AChild the path to check
|
|
|
|
* @param AParent the path which is supposed to be the parent
|
2005-02-15 16:02:57 +01:00
|
|
|
* @param AFailIfSame if True, fails if the child path is the parent path
|
2005-02-11 10:22:38 +01:00
|
|
|
* @result True if the child is indeed a child of the parent,
|
|
|
|
* False otherwise.
|
|
|
|
*}
|
2005-02-15 16:02:57 +01:00
|
|
|
function ChildPath(const AChild, AParent: String;
|
|
|
|
const AFailIfSame: Boolean = False): Boolean;
|
2005-02-11 10:22:38 +01:00
|
|
|
|
2005-02-15 13:36:31 +01:00
|
|
|
{** Determines if one path is the child of another path.
|
|
|
|
*
|
|
|
|
* Matches the start of two normalized paths. Either of the path may contain
|
|
|
|
* parent-references (ex. 'some\..\..\path\'). Note that the file system is
|
|
|
|
* not actually accessed, all checks are performed on the strings only.
|
|
|
|
*
|
|
|
|
* The parameters are modified to return the expanded file names, stripped
|
|
|
|
* of any trailing path delimiter.
|
|
|
|
*
|
|
|
|
* @param AChild the path to check
|
|
|
|
* @param AParent the path which is supposed to be the parent
|
2005-02-15 16:02:57 +01:00
|
|
|
* @param AFailIfSame if True, fails if the child path is the parent path
|
2005-02-15 13:36:31 +01:00
|
|
|
* @result True if the child is indeed a child of the parent,
|
|
|
|
* False otherwise.
|
|
|
|
*}
|
2005-02-15 16:02:57 +01:00
|
|
|
function ChildPathEx(var AChild, AParent: String;
|
|
|
|
const AFailIfSame: Boolean = False): Boolean;
|
2005-02-15 13:36:31 +01:00
|
|
|
|
2005-06-28 15:06:16 +02:00
|
|
|
function ReplacePart(const ASource: String; const AStart, ALength: Integer;
|
|
|
|
const AReplace: String): String;
|
|
|
|
|
2004-06-07 17:31:14 +02:00
|
|
|
implementation
|
|
|
|
uses
|
2005-06-28 15:06:16 +02:00
|
|
|
SysUtils,
|
|
|
|
Windows;
|
2004-06-07 17:31:14 +02:00
|
|
|
|
2005-11-30 19:17:03 +01:00
|
|
|
function FormatSize(const ABytes: Int64; AKeepBytes: Boolean;
|
|
|
|
const AFormat: String): String;
|
2004-06-07 17:31:14 +02:00
|
|
|
const
|
|
|
|
KB = 1024;
|
|
|
|
MB = KB * 1024;
|
|
|
|
GB = MB * 1024;
|
|
|
|
|
|
|
|
var
|
|
|
|
dSize: Double;
|
|
|
|
sExt: String;
|
|
|
|
|
|
|
|
begin
|
|
|
|
sExt := ' bytes';
|
2004-12-28 15:35:31 +01:00
|
|
|
dSize := ABytes;
|
2004-06-07 17:31:14 +02:00
|
|
|
|
2004-12-28 15:35:31 +01:00
|
|
|
if (not AKeepBytes) and (ABytes >= KB) then
|
|
|
|
if (ABytes >= KB) and (ABytes < MB) then begin
|
2004-06-07 17:31:14 +02:00
|
|
|
// 1 kB ~ 1 MB
|
2004-12-28 15:35:31 +01:00
|
|
|
dSize := ABytes / KB;
|
2004-06-07 17:31:14 +02:00
|
|
|
sExt := ' KB';
|
2004-12-28 15:35:31 +01:00
|
|
|
end else if (ABytes >= MB) and (ABytes < GB) then begin
|
2004-06-07 17:31:14 +02:00
|
|
|
// 1 MB ~ 1 GB
|
2004-12-28 15:35:31 +01:00
|
|
|
dSize := ABytes / MB;
|
2004-06-07 17:31:14 +02:00
|
|
|
sExt := ' MB';
|
|
|
|
end else begin
|
|
|
|
// 1 GB ~ x
|
2004-12-28 15:35:31 +01:00
|
|
|
dSize := ABytes / GB;
|
2004-06-07 17:31:14 +02:00
|
|
|
sExt := ' GB';
|
|
|
|
end;
|
|
|
|
|
2005-11-30 19:17:03 +01:00
|
|
|
Result := FormatFloat(AFormat, dSize) + sExt;
|
2004-06-07 17:31:14 +02:00
|
|
|
end;
|
|
|
|
|
2005-02-11 10:22:38 +01:00
|
|
|
function CompareTextL(const AMatch, AAgainst: String;
|
|
|
|
const ALength: Integer): Integer;
|
2004-08-22 17:03:02 +02:00
|
|
|
var
|
|
|
|
sMatch: String;
|
|
|
|
sAgainst: String;
|
|
|
|
|
|
|
|
begin
|
|
|
|
// If there is no reason to copy; don't.
|
|
|
|
if Length(AMatch) <= ALength then
|
|
|
|
sMatch := AMatch
|
|
|
|
else
|
|
|
|
sMatch := Copy(AMatch, 1, ALength);
|
|
|
|
|
|
|
|
if Length(AAgainst) <= ALength then
|
|
|
|
sAgainst := AAgainst
|
|
|
|
else
|
|
|
|
sAgainst := Copy(AAgainst, 1, ALength);
|
|
|
|
|
|
|
|
Result := CompareText(sMatch, sAgainst);
|
|
|
|
end;
|
|
|
|
|
2005-02-11 10:22:38 +01:00
|
|
|
function SameTextL(const AMatch, AAgainst: String;
|
|
|
|
const ALength: Integer): Boolean;
|
2004-08-22 17:03:02 +02:00
|
|
|
begin
|
|
|
|
Result := (CompareTextL(AMatch, AAgainst, ALength) = 0);
|
|
|
|
end;
|
|
|
|
|
2005-02-11 10:22:38 +01:00
|
|
|
function CompareTextS(const AMatch, AAgainst: String): Integer;
|
2004-08-22 17:03:02 +02:00
|
|
|
begin
|
|
|
|
Result := CompareTextL(AMatch, AAgainst, Length(AAgainst));
|
|
|
|
end;
|
|
|
|
|
2005-02-11 10:22:38 +01:00
|
|
|
function SameTextS(const AMatch, AAgainst: String): Boolean;
|
2004-08-22 17:03:02 +02:00
|
|
|
begin
|
|
|
|
Result := SameTextL(AMatch, AAgainst, Length(AAgainst));
|
|
|
|
end;
|
|
|
|
|
2004-09-02 16:24:30 +02:00
|
|
|
|
2014-04-03 16:03:28 +02:00
|
|
|
procedure Split(const ASource, ADelimiter: String; out ADest: TStringDynArray; ASkipEmptyItems: Boolean);
|
2004-09-02 16:24:30 +02:00
|
|
|
// StrPos is slow. Sloooooow slow. This function may not be advanced or
|
|
|
|
// the fastest one around, but it sure kicks StrPos' ass.
|
|
|
|
// 11.5 vs 1.7 seconds on a 2.4 Ghz for 10.000 iterations, baby!
|
|
|
|
function StrPosEx(const ASource, ASearch: PChar): PChar;
|
|
|
|
var
|
|
|
|
pPos: PChar;
|
|
|
|
pSub: PChar;
|
|
|
|
|
|
|
|
begin
|
|
|
|
Result := nil;
|
|
|
|
|
|
|
|
// Search for the first character
|
|
|
|
pPos := ASource;
|
|
|
|
|
|
|
|
while pPos^ <> #0 do
|
|
|
|
begin
|
|
|
|
if pPos^ = ASearch^ then
|
|
|
|
begin
|
|
|
|
// Found the first character, match the rest
|
|
|
|
pSub := ASearch;
|
|
|
|
Result := pPos;
|
|
|
|
Inc(pSub);
|
|
|
|
Inc(pPos);
|
|
|
|
|
|
|
|
|
|
|
|
while pSub^ <> #0 do
|
|
|
|
begin
|
|
|
|
if pPos^ <> pSub^ then
|
|
|
|
begin
|
|
|
|
// No match, resume as normal
|
|
|
|
Result := nil;
|
|
|
|
break;
|
|
|
|
end;
|
|
|
|
|
|
|
|
Inc(pSub);
|
|
|
|
Inc(pPos);
|
|
|
|
end;
|
|
|
|
|
|
|
|
// If still assigned, all characters matched
|
|
|
|
if Assigned(Result) then
|
|
|
|
exit;
|
|
|
|
end else
|
|
|
|
Inc(pPos);
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
|
|
const
|
|
|
|
GrowStart = 32;
|
|
|
|
GrowMax = 256;
|
|
|
|
|
|
|
|
var
|
2014-04-03 16:03:28 +02:00
|
|
|
capacity: Integer;
|
|
|
|
count: Integer;
|
|
|
|
delimiterLength: Integer;
|
|
|
|
sourceLength: Integer;
|
|
|
|
position: Integer;
|
|
|
|
size: Integer;
|
|
|
|
delimiter: PChar;
|
|
|
|
lastPos: PChar;
|
|
|
|
currentPos: PChar;
|
2004-09-02 16:24:30 +02:00
|
|
|
|
|
|
|
begin
|
|
|
|
// Reserve some space
|
2014-04-03 16:03:28 +02:00
|
|
|
capacity := GrowStart;
|
|
|
|
count := 0;
|
|
|
|
SetLength(ADest, capacity);
|
2004-09-02 16:24:30 +02:00
|
|
|
|
2014-04-03 16:03:28 +02:00
|
|
|
delimiterLength := Length(ADelimiter);
|
|
|
|
sourceLength := Length(ASource);
|
|
|
|
position := 0;
|
|
|
|
delimiter := PChar(ADelimiter);
|
|
|
|
currentPos := PChar(ASource);
|
2004-09-02 16:24:30 +02:00
|
|
|
|
|
|
|
repeat
|
|
|
|
// Find delimiter
|
2014-04-03 16:03:28 +02:00
|
|
|
lastPos := currentPos;
|
|
|
|
currentPos := StrPosEx(currentPos, delimiter);
|
2004-09-02 16:24:30 +02:00
|
|
|
|
2014-04-03 16:03:28 +02:00
|
|
|
if currentPos <> nil then
|
2004-09-02 16:24:30 +02:00
|
|
|
begin
|
2014-04-03 16:03:28 +02:00
|
|
|
size := (Integer(currentPos) - Integer(lastPos)) div SizeOf(Char);
|
|
|
|
|
|
|
|
if (size > 0) or (not ASkipEmptyItems) then
|
2004-09-02 16:24:30 +02:00
|
|
|
begin
|
2014-04-03 16:03:28 +02:00
|
|
|
// Make space
|
|
|
|
Inc(count);
|
|
|
|
if count > capacity then
|
|
|
|
begin
|
|
|
|
if capacity < GrowMax then
|
|
|
|
Inc(capacity, capacity)
|
|
|
|
else
|
|
|
|
Inc(capacity, GrowMax);
|
2004-09-02 16:24:30 +02:00
|
|
|
|
2014-04-03 16:03:28 +02:00
|
|
|
SetLength(ADest, capacity);
|
|
|
|
end;
|
2004-09-02 16:24:30 +02:00
|
|
|
|
2014-04-03 16:03:28 +02:00
|
|
|
// Copy substring
|
|
|
|
SetString(ADest[count - 1], lastPos, size);
|
|
|
|
end;
|
2004-09-02 16:24:30 +02:00
|
|
|
|
|
|
|
// Move pointer
|
2014-04-03 16:03:28 +02:00
|
|
|
Inc(currentPos, delimiterLength);
|
|
|
|
Inc(position, size + delimiterLength);
|
2004-09-02 16:24:30 +02:00
|
|
|
end else
|
|
|
|
begin
|
2014-04-03 16:03:28 +02:00
|
|
|
if position < sourceLength then
|
2004-09-02 16:24:30 +02:00
|
|
|
begin
|
|
|
|
// Copy what's left
|
2014-04-03 16:03:28 +02:00
|
|
|
Inc(count);
|
|
|
|
if count > capacity then
|
|
|
|
SetLength(ADest, count);
|
2004-09-02 16:24:30 +02:00
|
|
|
|
2014-04-03 16:03:28 +02:00
|
|
|
ADest[count - 1] := lastPos;
|
2004-09-02 16:24:30 +02:00
|
|
|
end;
|
|
|
|
|
2014-04-03 16:03:28 +02:00
|
|
|
if count <> capacity then
|
2004-09-02 16:24:30 +02:00
|
|
|
// Shrink array
|
2014-04-03 16:03:28 +02:00
|
|
|
SetLength(ADest, count);
|
2004-09-02 16:24:30 +02:00
|
|
|
|
|
|
|
break;
|
|
|
|
end;
|
|
|
|
until False;
|
|
|
|
end;
|
|
|
|
|
2013-10-02 22:38:15 +02:00
|
|
|
|
|
|
|
function Join(ASource: array of string; const AGlue: string; ASkipEmptyItems: Boolean): string;
|
2004-10-30 14:28:39 +02:00
|
|
|
var
|
2013-10-02 22:38:15 +02:00
|
|
|
totalLength: Integer;
|
|
|
|
itemIndex: Integer;
|
|
|
|
itemLength: Integer;
|
|
|
|
itemCount: Integer;
|
|
|
|
glueLength: Integer;
|
|
|
|
resultPos: PChar;
|
|
|
|
firstItem: Boolean;
|
2004-10-30 14:28:39 +02:00
|
|
|
|
|
|
|
begin
|
|
|
|
if High(ASource) = -1 then
|
|
|
|
begin
|
|
|
|
Result := '';
|
|
|
|
exit;
|
|
|
|
end;
|
|
|
|
|
2013-10-02 22:38:15 +02:00
|
|
|
{ Om geheugen-reallocaties te verminderen, vantevoren even
|
|
|
|
uitrekenen hoe groot het resultaat gaat worden. }
|
|
|
|
itemCount := 0;
|
|
|
|
totalLength := 0;
|
2004-10-30 14:28:39 +02:00
|
|
|
|
2013-10-02 22:38:15 +02:00
|
|
|
for itemIndex := High(ASource) downto Low(ASource) do
|
|
|
|
begin
|
|
|
|
if (not ASkipEmptyItems) or (Length(ASource[itemIndex]) > 0) then
|
|
|
|
begin
|
|
|
|
Inc(totalLength, Length(ASource[itemIndex]));
|
|
|
|
Inc(itemCount);
|
|
|
|
end;
|
|
|
|
end;
|
2004-10-30 14:28:39 +02:00
|
|
|
|
2013-10-02 22:38:15 +02:00
|
|
|
glueLength := Length(AGlue);
|
|
|
|
Inc(totalLength, Pred(itemCount) * glueLength);
|
|
|
|
|
|
|
|
SetLength(Result, totalLength);
|
2004-10-30 14:28:39 +02:00
|
|
|
|
2013-10-02 22:38:15 +02:00
|
|
|
firstItem := True;
|
|
|
|
resultPos := PChar(Result);
|
2004-10-30 14:28:39 +02:00
|
|
|
|
2013-10-02 22:38:15 +02:00
|
|
|
for itemIndex := Low(ASource) to High(ASource) do
|
2004-10-30 14:28:39 +02:00
|
|
|
begin
|
2013-10-02 22:38:15 +02:00
|
|
|
itemLength := Length(ASource[itemIndex]);
|
2004-10-30 14:28:39 +02:00
|
|
|
|
2013-10-02 22:38:15 +02:00
|
|
|
if (not ASkipEmptyItems) or (itemLength > 0) then
|
|
|
|
begin
|
|
|
|
if not firstItem then
|
|
|
|
begin
|
2014-10-28 19:56:47 +01:00
|
|
|
Move(PChar(AGlue)^, resultPos^, glueLength * SizeOf(Char));
|
2013-10-02 22:38:15 +02:00
|
|
|
Inc(resultPos, glueLength);
|
|
|
|
end else
|
|
|
|
firstItem := False;
|
|
|
|
|
2014-10-28 19:56:47 +01:00
|
|
|
Move(PChar(ASource[itemIndex])^, resultPos^, itemLength * SizeOf(Char));
|
2013-10-02 22:38:15 +02:00
|
|
|
Inc(resultPos, itemLength);
|
|
|
|
end;
|
2004-10-30 14:28:39 +02:00
|
|
|
end;
|
|
|
|
end;
|
|
|
|
|
2005-02-11 10:22:38 +01:00
|
|
|
|
2013-10-02 22:38:15 +02:00
|
|
|
|
2005-02-15 16:02:57 +01:00
|
|
|
function ChildPath(const AChild, AParent: String;
|
|
|
|
const AFailIfSame: Boolean): Boolean;
|
2005-02-11 10:22:38 +01:00
|
|
|
var
|
|
|
|
sChild: String;
|
|
|
|
sParent: String;
|
|
|
|
|
|
|
|
begin
|
2005-02-15 13:36:31 +01:00
|
|
|
sChild := AChild;
|
|
|
|
sParent := AParent;
|
2005-02-15 16:02:57 +01:00
|
|
|
Result := ChildPathEx(sChild, sParent, AFailIfSame);
|
2005-02-15 13:36:31 +01:00
|
|
|
end;
|
|
|
|
|
2005-02-15 16:02:57 +01:00
|
|
|
function ChildPathEx(var AChild, AParent: String;
|
|
|
|
const AFailIfSame: Boolean): Boolean;
|
2005-02-15 13:36:31 +01:00
|
|
|
begin
|
|
|
|
AChild := ExcludeTrailingPathDelimiter(ExpandFileName(AChild));
|
|
|
|
AParent := ExcludeTrailingPathDelimiter(ExpandFileName(AParent));
|
2005-02-15 16:02:57 +01:00
|
|
|
Result := SameTextS(AChild, AParent) and
|
|
|
|
((not AFailIfSame) or
|
2005-02-15 16:03:45 +01:00
|
|
|
(Length(AChild) > Length(AParent)));
|
2005-02-11 10:22:38 +01:00
|
|
|
end;
|
|
|
|
|
2005-06-28 15:06:16 +02:00
|
|
|
|
|
|
|
function ReplacePart(const ASource: String; const AStart, ALength: Integer;
|
|
|
|
const AReplace: String): String;
|
|
|
|
var
|
|
|
|
iSrcLength: Integer;
|
|
|
|
iLength: Integer;
|
|
|
|
iDiff: Integer;
|
|
|
|
iDest: Integer;
|
|
|
|
|
|
|
|
begin
|
2014-10-28 19:56:47 +01:00
|
|
|
iSrcLength := Length(ASource) * SizeOf(Char);
|
|
|
|
iLength := Length(AReplace) * SizeOf(Char);
|
2005-06-28 15:06:16 +02:00
|
|
|
iDiff := iLength - ALength;
|
|
|
|
iDest := 1;
|
|
|
|
|
|
|
|
SetLength(Result, iSrcLength + iDiff);
|
|
|
|
|
|
|
|
// Write first part
|
|
|
|
CopyMemory(@Result[iDest], @ASource[1], AStart - 1);
|
|
|
|
Inc(iDest, AStart - 1);
|
|
|
|
|
|
|
|
// Write replacement
|
|
|
|
CopyMemory(@Result[iDest], @AReplace[1], iLength);
|
|
|
|
Inc(iDest, iLength);
|
|
|
|
|
|
|
|
// Write last part
|
|
|
|
CopyMemory(@Result[iDest], @ASource[AStart + ALength],
|
|
|
|
iSrcLength - AStart - (ALength - 1));
|
|
|
|
end;
|
|
|
|
|
2004-06-07 17:31:14 +02:00
|
|
|
end.
|
2004-08-22 17:03:02 +02:00
|
|
|
|