unit dxVariantStream;
interface
uses
Windows;
type
TdxVariantEncoder =
class(TObject)
private
FData: Pointer;
FSize: Int64;
protected
function CalculateDataSize(V: Variant): Cardinal;
function WriteValue(Offset: Cardinal; V: Variant): Cardinal;
public
procedure Append(Value: Variant);
overload;
procedure Append(Values:
array of Variant);
overload;
constructor Create;
destructor Destroy;
override;
property Data: Pointer
read FData;
property Size: Int64
read FSize;
end;
TdxVariantDecoder =
class(TObject)
private
FIndexMap:
array of Cardinal;
FItemCount: Integer;
FData: Pointer;
protected
function GetVariantItem(I: Integer): Variant;
public
constructor Create(Data: Pointer; Size: Int64);
destructor Destroy;
override;
property Items[
Index: Integer]: Variant
read GetVariantItem;
default;
property ItemCount: Integer
read FItemCount;
end;
implementation
uses
dxException;
type
ECommandParserException =
class(
Exception);
{ TCommandEncoder }
procedure TdxVariantEncoder.Append(Value: Variant);
var
Offset: Cardinal;
begin
Offset := FSize;
FSize := FSize + CalculateDataSize(Value);
if Assigned(FData)
then
begin
ReallocMem(FData, FSize);
end else
begin
GetMem(FData, FSize);
end;
WriteValue(Offset, Value);
end;
procedure TdxVariantEncoder.Append(Values:
array of Variant);
var
BufferSize, Offset: Cardinal;
I: Integer;
begin
BufferSize := 0;
for I := Low(Values)
to High(Values)
do
begin
Inc(BufferSize, CalculateDataSize(Values[I]));
end;
Offset := FSize;
FSize := FSize + BufferSize;
if Assigned(FData)
then
begin
ReallocMem(FData, FSize);
end else
begin
GetMem(FData, FSize);
end;
for I := Low(Values)
to High(Values)
do
begin
Inc(Offset, WriteValue(Offset, Values[I]));
end;
end;
constructor TdxVariantEncoder.Create;
begin
inherited Create;
FSize := 0;
end;
destructor TdxVariantEncoder.Destroy;
begin
if Assigned(FData)
then
begin
FreeMem(FData);
end;
inherited;
end;
function TdxVariantEncoder.WriteValue(Offset: Cardinal; V: Variant): Cardinal;
var
VarData: TVarData;
begin
Result := 0;
VarData := TVarData(V);
case VarData.VType
of
varSmallInt:
begin
PByte(Cardinal(FData) + Offset)^ := $0;
PSmallInt(Cardinal(FData) + Offset + 1)^ := VarData.VSmallInt;
Result := 1 + SizeOf(SmallInt);
end;
varInteger:
begin
PByte(Cardinal(FData) + Offset)^ := $1;
PInteger(Cardinal(FData) + Offset + 1)^ := VarData.VInteger;
Result := 1 + SizeOf(Integer);
end;
varSingle:
begin
PByte(Cardinal(FData) + Offset)^ := $2;
PSingle(Cardinal(FData) + Offset + 1)^ := VarData.VSingle;
Result := 1 + SizeOf(Single);
end;
varDouble:
begin
PByte(Cardinal(FData) + Offset)^ := $3;
PDouble(Cardinal(FData) + Offset + 1)^ := VarData.VDouble;
Result := 1 + SizeOf(Double);
end;
varCurrency:
begin
PByte(Cardinal(FData) + Offset)^ := $4;
PCurrency(Cardinal(FData) + Offset + 1)^ := VarData.VCurrency;
Result := 1 + SizeOf(Currency);
end;
varDate:
begin
PByte(Cardinal(FData) + Offset)^ := $5;
PDateTime(Cardinal(FData) + Offset + 1)^ := VarData.VDate;
Result := 1 + SizeOf(TDateTime);
end;
varBoolean:
begin
PByte(Cardinal(FData) + Offset)^ := $6;
PWordBool(Cardinal(FData) + Offset + 1)^ := VarData.VBoolean;
Result := 1 + SizeOf(WordBool);
end;
varShortInt:
begin
PByte(Cardinal(FData) + Offset)^ := $7;
PShortInt(Cardinal(FData) + Offset + 1)^ := VarData.VShortInt;
Result := 1 + SizeOf(ShortInt);
end;
varByte:
begin
PByte(Cardinal(FData) + Offset)^ := $8;
PByte(Cardinal(FData) + Offset + 1)^ := VarData.VByte;
Result := 1 + SizeOf(Byte);
end;
varWord:
begin
PByte(Cardinal(FData) + Offset)^ := $9;
PWord(Cardinal(FData) + Offset + 1)^ := VarData.VWord;
Result := 1 + SizeOf(Word);
end;
varLongWord:
begin
PByte(Cardinal(FData) + Offset)^ := $A;
PLongWord(Cardinal(FData) + Offset + 1)^ := VarData.VLongWord;
Result := 1 + SizeOf(LongWord);
end;
varInt64:
begin
PByte(Cardinal(FData) + Offset)^ := $B;
PInt64(Cardinal(FData) + Offset + 1)^ := VarData.VInt64;
Result := 1 + SizeOf(Int64);
end;
varUInt64:
begin
PByte(Cardinal(FData) + Offset)^ := $C;
PUInt64(Cardinal(FData) + Offset + 1)^ := VarData.VUInt64;
Result := 1 + SizeOf(UInt64);
end;
varString:
begin
PByte(Cardinal(FData) + Offset)^ := $D;
Result := Length(AnsiString(VarData.VString)) * SizeOf(AnsiChar);
PCardinal(Cardinal(FData) + Offset + 1)^ := Result;
CopyMemory(Pointer(Cardinal(FData) + Offset + 5), VarData.VString,
Result);
Inc(Result, 5);
end;
varUString:
begin
PByte(Cardinal(FData) + Offset)^ := $E;
Result := Length(AnsiString(VarData.VUString)) * SizeOf(WideChar);
PCardinal(Cardinal(FData) + Offset + 1)^ := Result;
CopyMemory(Pointer(Cardinal(FData) + Offset + 5), VarData.VUString,
Result);
Inc(Result, 5);
end;
end;
end;
function TdxVariantEncoder.CalculateDataSize(V: Variant): Cardinal;
var
VarData: TVarData;
begin
Result := 0;
VarData := TVarData(V);
case VarData.VType
of
varSmallInt: Result := 1 + SizeOf(SmallInt);
varInteger: Result := 1 + SizeOf(Integer);
varSingle: Result := 1 + SizeOf(Single);
varDouble: Result := 1 + SizeOf(Double);
varCurrency: Result := 1 + SizeOf(Currency);
varDate: Result := 1 + SizeOf(TDateTime);
varBoolean: Result := 1 + SizeOf(WordBool);
varShortInt: Result := 1 + SizeOf(ShortInt);
varByte: Result := 1 + SizeOf(Byte);
varWord: Result := 1 + SizeOf(Word);
varLongWord: Result := 1 + SizeOf(LongWord);
varInt64: Result := 1 + SizeOf(Int64);
varUInt64: Result := 1 + SizeOf(UInt64);
varString: Result :=
5 + Length(AnsiString(VarData.VString)) * SizeOf(AnsiChar);
varUString: Result :=
5 + Length(AnsiString(VarData.VUString)) * SizeOf(WideChar);
end;
end;
{ TCommandDecoder }
constructor TdxVariantDecoder.Create(Data: Pointer; Size: Int64);
var
Offset: Cardinal;
begin
inherited Create;
FData := Data;
FItemCount := 0;
Offset := 0;
while (Offset < Size)
do
begin
Inc(FItemCount);
SetLength(FIndexMap, FItemCount);
FIndexMap[FItemCount - 1] := Offset;
case PByte(Cardinal(FData) + Offset)^
of
$0: Inc(Offset, 1 + SizeOf(SmallInt));
$1: Inc(Offset, 1 + SizeOf(Integer));
$2: Inc(Offset, 1 + SizeOf(Single));
$3: Inc(Offset, 1 + SizeOf(Double));
$4: Inc(Offset, 1 + SizeOf(Currency));
$5: Inc(Offset, 1 + SizeOf(TDateTime));
$6: Inc(Offset, 1 + SizeOf(WordBool));
$7: Inc(Offset, 1 + SizeOf(ShortInt));
$8: Inc(Offset, 1 + SizeOf(Byte));
$9: Inc(Offset, 1 + SizeOf(Word));
$A: Inc(Offset, 1 + SizeOf(LongWord));
$B: Inc(Offset, 1 + SizeOf(Int64));
$C: Inc(Offset, 1 + SizeOf(UInt64));
$D: Inc(Offset, 5 + PCardinal(DWord(FData) + Offset + 1)^);
$E: Inc(Offset, 5 + PCardinal(DWord(FData) + Offset + 1)^);
end;
end;
end;
destructor TdxVariantDecoder.Destroy;
begin
inherited;
end;
function TdxVariantDecoder.GetVariantItem(I: Integer): Variant;
var
DataType: Byte;
VarData: TVarData;
A: AnsiString;
W: WideString;
Size: Cardinal;
begin
if (
not (I
in [Low(FIndexMap) .. High(FIndexMap)]))
then
begin
raise ECommandParserException.Create('
Data table index out of bounds.');
end;
DataType := PByte(DWord(FData) + FIndexMap[I])^;
case DataType
of
$0: Result := PSmallInt(Cardinal(FData) + FIndexMap[I] + 1)^;
$1: Result := PInteger(Cardinal(FData) + FIndexMap[I] + 1)^;
$2: Result := PSingle(Cardinal(FData) + FIndexMap[I] + 1)^;
$3: Result := PDouble(Cardinal(FData) + FIndexMap[I] + 1)^;
$4: Result := PCurrency(Cardinal(FData) + FIndexMap[I] + 1)^;
$5: Result := PDateTime(Cardinal(FData) + FIndexMap[I] + 1)^;
$6: Result := PWordBool(Cardinal(FData) + FIndexMap[I] + 1)^;
$7: Result := PShortInt(Cardinal(FData) + FIndexMap[I] + 1)^;
$8: Result := PByte(Cardinal(FData) + FIndexMap[I] + 1)^;
$9: Result := PWord(Cardinal(FData) + FIndexMap[I] + 1)^;
$A: Result := PLongWord(Cardinal(FData) + FIndexMap[I] + 1)^;
$B: Result := PInt64(Cardinal(FData) + FIndexMap[I] + 1)^;
$C: Result := PUInt64(Cardinal(FData) + FIndexMap[I] + 1)^;
$D:
begin
VarData.VType := varString;
Size := PCardinal(Cardinal(FData) + FIndexMap[I] + 1)^;
SetLength(A, Size
div SizeOf(AnsiChar));
CopyMemory(@A[1], Pointer(Cardinal(FData) + FIndexMap[I] + 5), Size);
Result := A;
end;
$E:
begin
VarData.VType := varUString;
Size := PCardinal(Cardinal(FData) + FIndexMap[I] + 1)^;
SetLength(W, Size
div SizeOf(WideChar));
CopyMemory(@W[1], Pointer(Cardinal(FData) + FIndexMap[I] + 5), Size);
Result := W;
end;
end;
end;
end.