Subversion Repositories decoder

Compare Revisions

Regard whitespace Rev 1 → Rev 2

/trunk/VCL_DEC/DECFmt.pas
0,0 → 1,903
{Copyright: Hagen Reddmann HaReddmann at T-Online dot de
Author: Hagen Reddmann
Version: 5.1, Delphi Encryption Compendium
Delphi 5-7, BCB 3-4, designed and testet under D5
Description: Format Konvertion Utilitys for the DEC Packages
known Problems: none
Remarks: freeware, but this Copyright must be included
add about 10Kb code if all TFormats used
designed to made universal code, not very fast implementations
use lookup tables and formats can contains special chars
 
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
}
 
unit DECFmt;
 
interface
 
uses Windows, SysUtils, Classes, DECUtil;
 
{$I VER.INC}
 
type
TDECFormat = class;
 
TFormat_Copy = class; // copy input to output, it's the Default Format, eg FormaClass = nil
TFormat_HEX = class; // HEXadecimal in UpperCase
TFormat_HEXL = class; // HEXadecimal in Lowercase
TFormat_MIME32 = class; // MIME like format for Base 32
TFormat_MIME64 = class; // MIME Base 64 format
TFormat_PGP = class; // PGP's MIME Base 64 with PGP's Checksums
TFormat_UU = class; // Unix UU Base 64
TFormat_XX = class; // Unix XX base 64
TFormat_ESCAPE = class; // Escaped Strings
 
TDECFormatClass = class of TDECFormat;
 
TDECFormat = class(TDECObject) // for binary one to one convert = fmtCOPY
protected
class function DoEncode(const Value; Size: Integer): Binary; virtual; abstract;
class function DoDecode(const Value; Size: Integer): Binary; virtual; abstract;
class function DoIsValid(const Value; Size: Integer): Boolean; virtual; abstract;
public
class function Encode(const Value: Binary): Binary; overload;
class function Encode(const Value; Size: Integer): Binary; overload;
class function Decode(const Value: Binary): Binary; overload;
class function Decode(const Value; Size: Integer): Binary; overload;
class function IsValid(const Value: Binary): Boolean; overload;
class function IsValid(const Value; Size: Integer): Boolean; overload;
end;
 
TFormat_Copy = class(TDECFormat)
protected
class function DoEncode(const Value; Size: Integer): Binary; override;
class function DoDecode(const Value; Size: Integer): Binary; override;
class function DoIsValid(const Value; Size: Integer): Boolean; override;
end;
 
TFormat_HEX = class(TDECFormat) // Hexadecimal = fmtHEX
protected
class function DoEncode(const Value; Size: Integer): Binary; override;
class function DoDecode(const Value; Size: Integer): Binary; override;
class function DoIsValid(const Value; Size: Integer): Boolean; override;
public
class function CharTable: PChar; virtual;
end;
 
TFormat_HEXL = class(TFormat_HEX) // Hexadecimal lowercase = fmtHEXL
public
class function CharTable: PChar; override;
end;
 
TFormat_MIME32 = class(TFormat_HEX) // MIME Base 32 = fmtMIME32
protected
class function DoEncode(const Value; Size: Integer): Binary; override;
class function DoDecode(const Value; Size: Integer): Binary; override;
public
class function CharTable: PChar; override;
end;
 
TFormat_MIME64 = class(TFormat_HEX) // MIME Base 64 = fmtMIME64
protected
class function DoEncode(const Value; Size: Integer): Binary; override;
class function DoDecode(const Value; Size: Integer): Binary; override;
public
class function CharTable: PChar; override;
end;
 
TFormat_PGP = class(TFormat_MIME64)
protected
class function DoExtractCRC(const Value; var Size: Integer): LongWord;
class function DoEncode(const Value; Size: Integer): Binary; override;
class function DoDecode(const Value; Size: Integer): Binary; override;
end;
 
TFormat_UU = class(TDECFormat) // UU Encode = fmtUU
protected
class function DoEncode(const Value; Size: Integer): Binary; override;
class function DoDecode(const Value; Size: Integer): Binary; override;
class function DoIsValid(const Value; Size: Integer): Boolean; override;
public
class function CharTable: PChar; virtual;
end;
 
TFormat_XX = class(TFormat_UU) // XX Encode = fmtXX
public
class function CharTable: PChar; override;
end;
 
TFormat_ESCAPE = class(TDECFormat)
protected
class function DoEncode(const Value; Size: Integer): Binary; override;
class function DoDecode(const Value; Size: Integer): Binary; override;
end;
 
function ValidFormat(FormatClass: TDECFormatClass = nil): TDECFormatClass;
function FormatByName(const Name: String): TDECFormatClass;
function FormatByIdentity(Identity: LongWord): TDECFormatClass;
// insert #13#10 Chars in Blocks from BlockSize
function InsertCR(const Value: String; BlockSize: Integer): String;
// delete all #13 and #10 Chars
function DeleteCR(const Value: String): String;
// format any String to a Block
function InsertBlocks(const Value, BlockStart, BlockEnd: String; BlockSize: Integer): String;
// remove any Block format
function RemoveBlocks(const Value, BlockStart, BlockEnd: String): String;
 
var
PGPCharsPerLine: Integer = 80;
 
implementation
 
uses CRC;
 
resourcestring
sStringFormatExists = 'String format "%d" not exists.';
sInvalidStringFormat = 'Input is not an valid %s Format.';
sInvalidFormatString = 'Input can not be convert to %s Format.';
sFormatNotRegistered = 'String format not registered.';
 
function ValidFormat(FormatClass: TDECFormatClass = nil): TDECFormatClass;
begin
if FormatClass <> nil then Result := FormatClass
else Result := TFormat_Copy;
end;
 
function FormatByName(const Name: String): TDECFormatClass;
begin
Result := TDECFormatClass(DECClassByName(Name, TDECFormat));
end;
 
function FormatByIdentity(Identity: LongWord): TDECFormatClass;
begin
Result := TDECFormatClass(DECClassByIdentity(Identity, TDECFormat));
end;
 
class function TDECFormat.Encode(const Value: Binary): Binary;
begin
Result := DoEncode(Value[1], Length(Value));
end;
 
class function TDECFormat.Encode(const Value; Size: Integer): Binary;
begin
Result := DoEncode(Value, Size);
end;
 
class function TDECFormat.Decode(const Value: Binary): Binary;
begin
Result := DoDecode(Value[1], Length(Value));
end;
 
class function TDECFormat.Decode(const Value; Size: Integer): Binary;
begin
Result := DoDecode(Value, Size);
end;
 
class function TDECFormat.IsValid(const Value: Binary): Boolean;
begin
Result := DoIsValid(Value[1], Length(Value));
end;
 
class function TDECFormat.IsValid(const Value; Size: Integer): Boolean;
begin
Result := DoIsValid(Value, Size);
end;
 
// .TFormat_Copy
class function TFormat_Copy.DoEncode(const Value; Size: Integer): Binary;
begin
SetLength(Result, Size);
Move(Value, Result[1], Size);
end;
 
class function TFormat_Copy.DoDecode(const Value; Size: Integer): Binary;
begin
SetLength(Result, Size);
Move(Value, Result[1], Size);
end;
 
class function TFormat_Copy.DoIsValid(const Value; Size: Integer): Boolean;
begin
Result := Size >= 0;
end;
 
function TableFind(Value: Char; Table: PChar; Len: Integer): Integer; assembler;
asm // Utility for TStringFormat_XXXXX
PUSH EDI
MOV EDI,EDX
REPNE SCASB
MOV EAX,0
JNE @@1
MOV EAX,EDI
SUB EAX,EDX
@@1: DEC EAX
POP EDI
end;
 
class function TFormat_HEX.DoEncode(const Value; Size: Integer): Binary;
var
S: PByte;
D,T: PChar;
begin
Result := '';
if Size <= 0 then Exit;
SetLength(Result, Size * 2);
T := CharTable;
D := PChar(Result);
S := PByte(@Value);
while Size > 0 do
begin
D[0] := T[S^ shr 4];
D[1] := T[S^ and $F];
Inc(D, 2);
Inc(S);
Dec(Size);
end;
end;
 
class function TFormat_HEX.DoDecode(const Value; Size: Integer): Binary;
var
S: PChar;
D: PByte;
T: PChar;
I,P: Integer;
HasIdent: Boolean;
begin
Result := '';
if Size <= 0 then Exit;
SetLength(Result, Size div 2 +1);
T := CharTable;
D := PByte(Result);
S := PChar(@Value);
I := 0;
HasIdent := False;
while Size > 0 do
begin
P := TableFind(S^, T, 18);
if P < 0 then P := TableFind(UpCase(S^), T, 16);
if P < 0 then
raise EDECException.CreateFmt(sInvalidStringFormat, [DECClassname(Self)]);
Inc(S);
if P >= 0 then
if P > 16 then
begin
if not HasIdent then
begin
HasIdent := True;
I := 0;
D := PByte(Result);
end;
end else
begin
if Odd(I) then
begin
D^ := D^ or P;
Inc(D);
end else D^ := P shl 4;
Inc(I);
end;
Dec(Size);
end;
SetLength(Result, PChar(D) - PChar(Result));
end;
 
class function TFormat_HEX.DoIsValid(const Value; Size: Integer): Boolean;
var
S,T: PChar;
L: Integer;
begin
Result := True;
T := CharTable;
L := StrLen(T);
S := PChar(@Value);
while Result and (Size > 0) do
if TableFind(S^, T, L) >= 0 then
begin
Dec(Size);
Inc(S);
end else Result := False;
end;
 
class function TFormat_HEX.CharTable: PChar; assembler;
asm
MOV EAX,OFFSET @@1
RET
@@1: DB '0123456789ABCDEF' // Table must be >= 18 Chars
DB 'X$ abcdefhHx()[]{},;:-_/\*+"''',9,10,13,0
end;
 
class function TFormat_HEXL.CharTable: PChar;
asm
MOV EAX,OFFSET @@1
RET
@@1: DB '0123456789abcdef' // Table must be >= 18 Chars
DB 'X$ ABCDEFhHx()[]{},;:-_/\*+"''',9,10,13,0
end;
 
class function TFormat_MIME32.DoEncode(const Value; Size: Integer): Binary;
var
S: PByteArray;
D,T: PChar;
I: Integer;
begin
Result := '';
if Size <= 0 then Exit;
Size := Size * 8;
SetLength(Result, Size div 5 + 5);
D := PChar(Result);
T := CharTable;
S := PByteArray(@Value);
I := 0;
while I < Size do
begin
D^ := T[PWord(@S[I shr 3])^ shr (I and $7) and $1F];
Inc(D);
Inc(I, 5);
end;
SetLength(Result, D - PChar(Result));
end;
 
class function TFormat_MIME32.DoDecode(const Value; Size: Integer): Binary;
var
S,T,D: PChar;
I,V: Integer;
begin
Result := '';
if Size <= 0 then Exit;
T := CharTable;
SetLength(Result, Size * 5 div 8);
D := PChar(Result);
FillChar(D^, Length(Result), 0);
S := PChar(@Value);
Size := Size * 5;
I := 0;
while I < Size do
begin
V := TableFind(S^, T, 32);
if V < 0 then V := TableFind(UpCase(S^), T, 32);
if V >= 0 then
begin
PWord(@D[I shr 3])^ := PWord(@D[I shr 3])^ or (V shl (I and $7));
Inc(I, 5);
end else Dec(Size, 5);
Inc(S);
end;
SetLength(Result, Size div 8);
end;
 
class function TFormat_MIME32.CharTable: PChar;
asm
MOV EAX,OFFSET @@1
RET // must be >= 32 Chars
@@1: DB 'abcdefghijklnpqrstuwxyz123456789'
DB ' =$()[]{},;:-_\*"''',9,10,13,0 // special and skipped chars
end;
 
class function TFormat_MIME64.DoEncode(const Value; Size: Integer): Binary;
var
B: Cardinal;
I: Integer;
D,T: PChar;
S: PByteArray;
begin
Result := '';
if Size <= 0 then Exit;
SetLength(Result, Size * 4 div 3 + 4);
D := PChar(Result);
T := CharTable;
S := PByteArray(@Value);
while Size >= 3 do
begin
Dec(Size, 3);
B := S[0] shl 16 or S[1] shl 8 or S[2];
D[0] := T[B shr 18 and $3F];
D[1] := T[B shr 12 and $3F];
D[2] := T[B shr 6 and $3F];
D[3] := T[B and $3F];
Inc(D, 4);
S := @S[3];
end;
while Size > 0 do
begin
B := 0;
for I := 0 to 2 do
begin
B := B shl 8;
if Size > 0 then
begin
B := B or S[0];
S := @S[1];
end;
Dec(Size);
end;
for I := 3 downto 0 do
begin
if Size < 0 then
begin
D[I] := T[64];
Inc(Size);
end else D[I] := T[B and $3F];
B := B shr 6;
end;
Inc(D, 4);
end;
SetLength(Result, D - PChar(Result));
end;
 
class function TFormat_MIME64.DoDecode(const Value; Size: Integer): Binary;
var
B: Cardinal;
J,I: Integer;
S,D,L,T: PChar;
begin
Result := '';
if Size <= 0 then Exit;
SetLength(Result, Size);
Move(Value, PChar(Result)^, Size);
T := CharTable;
D := PChar(Result);
S := D;
L := S + Size;
J := 0;
while S < L do
begin
B := 0;
J := 4;
while (J > 0) and (S < L) do
begin
I := TableFind(S^, T, 65);
Inc(S);
if I >= 0 then
if I < 64 then
begin
B := B shl 6 or Byte(I);
Dec(J);
end else L := S;
end;
if J > 0 then
if J >= 4 then
begin
J := 0;
Break;
end else B := B shl (6 * J);
I := 2;
while I >= 0 do
begin
D[I] := Char(B);
B := B shr 8;
Dec(I);
end;
Inc(D, 3);
end;
SetLength(Result, D - PChar(Result) - J);
end;
 
class function TFormat_MIME64.CharTable: PChar; assembler;
asm
MOV EAX,OFFSET @@1
RET // must be >= 65 Chars
@@1: DB 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='
DB ' $()[]{},;:-_\*"''',9,10,13,0 // special and skipped chars
end;
 
class function TFormat_PGP.DoExtractCRC(const Value; var Size: Integer): LongWord;
var
L: PChar;
C: Char;
R: String;
begin
Result := $FFFFFFFF;
C := CharTable[64]; // get padding char, per default '='
L := PChar(@Value) + Size;
while L <> PChar(@Value) do
if L^ = C then Break else Dec(L); // scan reverse for padding char
if L - PChar(@Value) >= Size - 5 then // remaining chars must be > 4 ,i.e. '=XQRT'
try
Inc(L);
R := inherited DoDecode(L^, Size - (L - PChar(@Value)));
if Length(R) >= 3 then
begin
Result := 0;
Move(PChar(R)^, Result, 3);
Size := L - PChar(@Value);
end;
except
end;
end;
 
class function TFormat_PGP.DoEncode(const Value; Size: Integer): Binary;
var
CRC: LongWord;
begin
Result := '';
if Size <= 0 then Exit;
Result := InsertCR(inherited DoEncode(Value, Size), PGPCharsPerLine); // 80 chars per line
CRC := CRCCalc(CRC_24, Value, Size); // calculate 24Bit Checksum
SwapBytes(CRC, 3); // PGP use Big Endian
if Result[Length(Result)] <> #10 then Result := Result + #13#10; // insert CR iff needed, CRC must be in next line
Result := Result + '=' + inherited DoEncode(CRC, 3); // append CRC
end;
 
class function TFormat_PGP.DoDecode(const Value; Size: Integer): Binary;
var
CRC: LongWord;
begin
Result := '';
if Size <= 0 then Exit;
CRC := DoExtractCRC(Value, Size);
Result := inherited DoDecode(Value, Size);
if CRC <> $FFFFFFFF then // iff CRC found check it
begin
SwapBytes(CRC, 3);
if CRC <> CRCCalc(CRC_24, PChar(Result)^, Length(Result)) then
raise EDECException.CreateFmt(sInvalidStringFormat, [DECClassname(Self)]);
end;
end;
 
class function TFormat_UU.DoEncode(const Value; Size: Integer): Binary;
var
S,T,D: PChar;
L,I: Integer;
B: Cardinal;
begin
Result := '';
if Size <= 0 then Exit;
SetLength(Result, Size * 4 div 3 + Size div 45 + 10);
D := PChar(Result);
T := CharTable;
S := PChar(@Value);
while Size > 0 do
begin
L := Size;
if L > 45 then L := 45;
Dec(Size, L);
D^ := T[L];
while L > 0 do
begin
B := 0;
for I := 0 to 2 do
begin
B := B shl 8;
if L > 0 then
begin
B := B or Byte(S^);
Inc(S);
end;
Dec(L);
end;
for I := 4 downto 1 do
begin
D[I] := T[B and $3F];
B := B shr 6;
end;
Inc(D, 4);
end;
Inc(D);
end;
SetLength(Result, D - PChar(Result));
end;
 
class function TFormat_UU.DoDecode(const Value; Size: Integer): Binary;
var
T,D,L,S: PChar;
I,E: Integer;
B: Cardinal;
begin
Result := '';
if Size <= 0 then Exit;
SetLength(Result, Size);
S := PChar(@Value);
L := S + Size;
D := PChar(Result);
T := CharTable;
repeat
Size := TableFind(S^, T, 64);
if (Size < 0) or (Size > 45) then
raise EDECException.CreateFmt(sInvalidStringFormat, [DECClassName(Self)]);
Inc(S);
while Size > 0 do
begin
B := 0;
I := 4;
while (I > 0) and (S <= L) do
begin
E := TableFind(S^, T, 64);
if E >= 0 then
begin
B := B shl 6 or Byte(E);
Dec(I);
end;
Inc(S);
end;
I := 2;
repeat
D[I] := Char(B);
B := B shr 8;
Dec(I);
until I < 0;
if Size > 3 then Inc(D, 3) else Inc(D, Size);
Dec(Size, 3);
end;
until S >= L;
SetLength(Result, D - PChar(Result));
end;
 
class function TFormat_UU.DoIsValid(const Value; Size: Integer): Boolean;
var
S,T: PChar;
L,I,P: Integer;
begin
Result := False;
T := CharTable;
L := StrLen(T);
S := PChar(@Value);
P := 0;
while Size > 0 do
begin
I := TableFind(S^, T, L);
if I >= 0 then
begin
Dec(Size);
Inc(S);
if P = 0 then
begin
if I > 45 then Exit;
P := (I * 4 + 2) div 3;
end else
if I < 64 then Dec(P);
end else Exit;
end;
if P <> 0 then Exit;
Result := True;
end;
 
class function TFormat_UU.CharTable: PChar;
asm
MOV EAX,OFFSET @@1
RET // must be >= 64 Chars
@@1: DB '`!"#$%&''()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_'
DB ' ',9,10,13,0
end;
 
class function TFormat_XX.CharTable: PChar;
asm
MOV EAX,OFFSET @@1
RET
@@1: DB '+-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
DB ' "()[]''',9,10,13,0
end;
 
const
ESCAPE_CodesL: PChar = 'abtnvfr';
ESCAPE_CodesU: PChar = 'ABTNVFR';
 
class function TFormat_ESCAPE.DoDecode(const Value; Size: Integer): Binary;
var
D,S,T: PChar;
I: Integer;
begin
Result := '';
if Size <= 0 then Exit;
SetLength(Result, Size);
D := PChar(Result);
S := PChar(@Value);
T := S + Size;
while S < T do
begin
if S^ = '\' then
begin
Inc(S);
if S > T then Break;
if UpCase(S^) = 'X' then
begin
if S + 2 > T then
raise EDECException.CreateFmt(sInvalidStringFormat, [DECClassName(Self)]);
I := TableFind(UpCase(S[1]), TFormat_HEX.CharTable, 16);
if I < 0 then
raise EDECException.CreateFmt(sInvalidStringFormat, [DECClassName(Self)]);
D^ := Char(I shl 4);
I := TableFind(UpCase(S[2]), TFormat_HEX.CharTable, 16);
if I < 0 then
raise EDECException.CreateFmt(sInvalidStringFormat, [DECClassName(Self)]);
D^ := Char(Byte(D^) or I);
Inc(S, 2);
end else
begin
I := TableFind(UpCase(S^), ESCAPE_CodesU, 7);
if I >= 0 then D^ := Char(I + 7)
else D^ := S^;
end;
end else D^ := S^;
Inc(D);
Inc(S);
end;
SetLength(Result, D - PChar(Result));
end;
 
class function TFormat_ESCAPE.DoEncode(const Value; Size: Integer): Binary;
var
S: PByte;
D,T: PChar;
I: Integer;
begin
Result := '';
if Size = 0 then Exit;
SetLength(Result, Size + 8);
I := Size;
D := PChar(Result);
S := PByte(@Value);
T := TFormat_HEX.CharTable;
while Size > 0 do
begin
if I <= 0 then
begin
I := D - PChar(Result);
SetLength(Result, I + Size + 8);
D := PChar(Result) + I;
I := Size;
end;
if (S^ < 32) {or (S^ > $7F)} then
if (S^ >= 7) and (S^ <= 13) then
begin
D[0] := '\';
D[1] := ESCAPE_CodesL[S^ - 7];
Inc(D, 2);
Dec(I, 2);
end else
begin
D[0] := '\';
D[1] := 'x';
D[2] := T[S^ shr 4];
D[3] := T[S^ and $F];
Inc(D, 4);
Dec(I, 4);
end
else
if S^ = Ord('\') then
begin
D[0] := '\';
D[1] := '\';
Inc(D, 2);
Dec(I, 2);
end else
if S^ = Ord('"') then
begin
D[0] := '\';
D[1] := '"';
Inc(D, 2);
Dec(I, 2);
end else
begin
D^ := Char(S^);
Inc(D);
Dec(I);
end;
Dec(Size);
Inc(S);
end;
SetLength(Result, D - PChar(Result));
end;
 
function InsertCR(const Value: String; BlockSize: Integer): String;
var
I: Integer;
S,D: PChar;
begin
if (BlockSize <= 0) or (Length(Value) <= BlockSize) then
begin
Result := Value;
Exit;
end;
I := Length(Value);
SetLength(Result, I + I * 2 div BlockSize + 2);
S := PChar(Value);
D := PChar(Result);
repeat
Move(S^, D^, BlockSize);
Inc(S, BlockSize);
Inc(D, BlockSize);
D^ := #13; Inc(D);
D^ := #10; Inc(D);
Dec(I, BlockSize);
until I < BlockSize;
Move(S^, D^, I);
Inc(D, I);
SetLength(Result, D - PChar(Result));
end;
 
function DeleteCR(const Value: String): String;
var
S,D: PChar;
I: Integer;
begin
I := Length(Value);
SetLength(Result, I);
D := PChar(Result);
S := PChar(Value);
while I > 0 do
begin
if (S^ <> #10) and (S^ <> #13) then
begin
D^ := S^;
Inc(D);
end;
Inc(S);
Dec(I);
end;
SetLength(Result, D - PChar(Result));
end;
 
function InsertBlocks(const Value, BlockStart, BlockEnd: String; BlockSize: Integer): String;
var
I,LS,LE: Integer;
D,S: PChar;
begin
if (BlockSize <= 0) or (Length(Value) <= BlockSize) then
begin
Result := Value;
Exit;
end;
I := Length(Value);
LS := Length(BlockStart);
LE := Length(BlockEnd);
SetLength(Result, I + (I div BlockSize + 1) * (LS + LE));
S := PChar(Value);
D := PChar(Result);
repeat
Move(PChar(BlockStart)^, D^, LS); Inc(D, LS);
Move(S^, D^, BlockSize); Inc(D, BlockSize);
Move(PChar(BlockEnd)^, D^, LE); Inc(D, LE);
Dec(I, BlockSize);
Inc(S, BlockSize);
until I < BlockSize;
if I > 0 then
begin
Move(PChar(BlockStart)^, D^, LS); Inc(D, LS);
Move(S^, D^, I); Inc(D, I);
Move(PChar(BlockEnd)^, D^, LE); Inc(D, LE);
end;
SetLength(Result, D - PChar(Result));
end;
 
function RemoveBlocks(const Value, BlockStart, BlockEnd: String): String;
var
LS,LE: Integer;
S,D,L,K: PChar;
begin
SetLength(Result, Length(Value));
LS := Length(BlockStart);
LE := Length(BlockEnd);
D := PChar(Result);
S := PChar(Value);
L := S + Length(Value);
repeat
if S > L then Break;
if LS > 0 then
begin
S := StrPos(S, PChar(BlockStart));
if S = nil then Break;
Inc(S, LS);
if S > L then Break;
end;
K := StrPos(S, PChar(BlockEnd));
if K = nil then K := L;
Move(S^, D^, K - S);
Inc(D, K - S);
S := K + LE;
until S >= L;
SetLength(Result, D - PChar(Result));
end;
 
end.