|
Registriert seit: 3. Sep 2004 4.629 Beiträge Delphi 10.2 Tokyo Starter |
#1
Delphi-Version: 2010
Hallo zusammen,
nun da ich das Problem mit TVarRec / Variant gelöst habe, presentiere ich hier mal die vorläufige Version des Protokolls. Die Unit besteht aus zwei Klassen: Der Encoder dient zum Erstellen des Pakets. Über die Methode Append() können Daten angehangen werden. Der Decoder kann Datensätze anhand ihrer Indizes aus dem fertigen Paket auslesen. Die Daten werden als Variant zurückgegeben. Praktisch könnte man also sagen, es handelt sich um eine Art Stream für Variants. ![]() ![]()
Delphi-Quellcode:
Hier noch ein kurzes Beispiel, wie die Klassen verwendet werden:
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.
Delphi-Quellcode:
Viele Grüße
procedure TForm6.Button1Click(Sender: TObject);
var Encoder: TdxVariantEncoder; Decoder: TdxVariantDecoder; begin Encoder := TdxVariantEncoder.Create; try Encoder.Append([1, -120000, 'testwide', AnsiString('testansi'), false]); Encoder.Append(Word(2)); Encoder.Append([Int64(33), 123.444]); Decoder := TdxVariantDecoder.Create(Encoder.Data, Encoder.Size); try ShowMessage(Decoder[3]); // testansi ShowMessage(Decoder[7]); // 123.444 finally Decoder.Free; end; finally Encoder.Free; end; end; Zacherl Geändert von Zacherl ( 4. Mai 2011 um 16:07 Uhr) |
![]() |
Ansicht |
![]() |
![]() |
![]() |
ForumregelnEs ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.
BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus. Trackbacks are an
Pingbacks are an
Refbacks are aus
|
|
Nützliche Links |
Heutige Beiträge |
Sitemap |
Suchen |
Code-Library |
Wer ist online |
Alle Foren als gelesen markieren |
Gehe zu... |
LinkBack |
![]() |
![]() |