键值对序列
支持delphi和lazarus。
/// <author>cxg 2022-4-25</author>
/// 支持 delphi and fpc.
/// 支持 linux and windows.
/// 键-值 数据序列: keyLen(integer)+keyName(rawbytestring)+valueLen(integer)+value
/// 测试: d7~d11,lazarus
unit keyValue.serialize;
interface
uses
FmtBcd, DateUtils, Variants, Classes, SysUtils;
const
pieceSize = 65536;
type
{$IFNDEF fpc}
{$IF RTLVersion<25}
IntPtr = integer;
{$IFEND IntPtr}
{$IF CompilerVersion < 18}// before delphi 2007
TBytes = array of byte;
{$IFEND}
{$IFNDEF UNICODE}
RawByteString = AnsiString;
PRawByteString = ^RawByteString;
{$ENDIF}
{$ENDIF}
TSerialize = class
private
fValue: TBytes;
fKey: rawbytestring;
fList: tlist;
private
procedure setInt(const keyName: rawbytestring; const Value: integer);
procedure setStr(const keyName: rawbytestring; const Value: rawbytestring);
procedure setVariant(const keyName: rawbytestring; const Value: variant);
procedure setBytes(const keyName: rawbytestring; const Value: TBytes);
procedure setDateTime(const keyName: rawbytestring; const Value: TDateTime);
procedure setBool(const keyName: rawbytestring; const Value: boolean);
procedure setSingle(const keyName: rawbytestring; const Value: single);
procedure setDouble(const keyName: rawbytestring; const Value: double);
procedure setByte(const keyName: rawbytestring; const Value: byte);
procedure setInt64(const keyName: rawbytestring; const Value: int64);
procedure setCurrency(const keyName: rawbytestring; const Value: Currency);
procedure setStream(const keyName: rawbytestring; const Value: tstream);
procedure setWord(const keyName: rawbytestring; const Value: word);
procedure setExtended(const keyName: rawbytestring; const Value: Extended);
procedure setLongWord(const keyName: rawbytestring; const Value: LongWord);
procedure setShortint(const keyName: rawbytestring; const Value: Shortint);
procedure setSmallint(const keyName: rawbytestring; const Value: Smallint);
procedure setBCD(const keyName: rawbytestring; const Value: tbcd);
private
function getInt(const keyName: rawbytestring): integer;
function getStr(const keyName: rawbytestring): rawbytestring;
function getVariant(const keyName: rawbytestring): variant;
function getBytes(const keyName: rawbytestring): TBytes;
function getDateTime(const keyName: rawbytestring): TDateTime;
function getBool(const keyName: rawbytestring): boolean;
function getSingle(const keyName: rawbytestring): single;
function getDouble(const keyName: rawbytestring): double;
function getByte(const keyName: rawbytestring): byte;
function getInt64(const keyName: rawbytestring): int64;
function getCurrency(const keyName: rawbytestring): Currency;
function getStream(const keyName: rawbytestring): tstream;
function getWord(const keyName: rawbytestring): word;
function getExtended(const keyName: rawbytestring): Extended;
function getLongWord(const keyName: rawbytestring): LongWord;
function getShortint(const keyName: rawbytestring): Shortint;
function getSmallint(const keyName: rawbytestring): Smallint;
function getBCD(const keyName: rawbytestring): tbcd;
private
function getCount: integer;
public
constructor Create;
destructor Destroy; override;
public
function key(const keyName: rawbytestring): TSerialize;
procedure Clear;
function Delete(const keyName: rawbytestring): boolean;
public
procedure marshal(stream: TStream);
function marshal2: TBytes;
function marshal3: RawByteString;
function marshal5: OleVariant;
public
procedure unMarshal(stream: TStream); overload;
procedure unMarshal(bytes: TBytes); overload;
procedure unMarshal(raw: RawByteString); overload;
procedure unMarshal(ole: OleVariant); overload;
public
property asInt[const keyName: rawbytestring]: integer read getInt write setInt;
property asStr[const keyName: rawbytestring]: rawbytestring read getStr write setStr;
property AsVariant[const keyName: rawbytestring]: variant read getVariant write setVariant;
property asBytes[const keyName: rawbytestring]: TBytes read getBytes write setBytes;
property AsDateTime[const keyName: rawbytestring]: TDateTime read getDateTime write setDateTime;
property asBool[const keyName: rawbytestring]: boolean read getBool write setBool;
property asSingle[const keyName: rawbytestring]: single read getSingle write setSingle;
property asDouble[const keyName: rawbytestring]: double read getDouble write setDouble;
property asByte[const keyName: rawbytestring]: byte read getByte write setByte;
property asInt64[const keyName: rawbytestring]: int64 read getInt64 write setInt64;
property asCurrency[const keyName: rawbytestring]: Currency read getCurrency write setCurrency;
property asStream[const keyName: rawbytestring]: tstream read getStream write setStream;
property asWord[const keyName: rawbytestring]: word read getword write setword;
property asExtended[const keyName: rawbytestring]: Extended read getExtended write setExtended;
property asLongWord[const keyName: rawbytestring]: LongWord read getLongWord write setLongWord;
property asShortint[const keyName: rawbytestring]: Shortint read getShortint write setShortint;
property asSmallint[const keyName: rawbytestring]: Smallint read getSmallint write setSmallint;
property asBCD[const keyName: rawbytestring]: tbcd read getBCD write setBCD;
property asFloat[const keyName: rawbytestring]: double read getDouble write setDouble;
property asCardinal[const keyName: rawbytestring]: LongWord read getLongWord write setLongWord;
public
property Count: integer read getCount;
end;
implementation
function TSerialize.key(const keyName: rawbytestring): TSerialize;
var
i: integer;
found: boolean;
begin
Result := nil;
found := False;
for i := 0 to fList.Count - 1 do
begin
if keyName = TSerialize(fList[i]).fKey then
begin
Result := TSerialize(fList[i]);
exit;
end;
end;
if not found then
begin
Result := TSerialize.Create;
Result.fKey := keyName;
fList.Add(Result);
end;
end;
function TSerialize.getInt(const keyName: rawbytestring): integer;
var
s: TSerialize;
begin
s := key(keyName);
Result := PInteger(s.fValue)^;
end;
function TSerialize.getStr(const keyName: rawbytestring): rawbytestring;
var
l: integer;
s: TSerialize;
begin
s := key(keyName);
l := Length(s.fValue);
if l = 0 then
Result := ''
else
begin
SetLength(Result, l);
Move(s.FValue[0], PRawByteString(Result)^, l);
end;
end;
function TSerialize.getStream(const keyName: rawbytestring): tstream;
var
s: TSerialize;
l, at, bufLen, remainLen: Integer;
p: pbyte;
begin
s := key(keyName);
l := Length(s.fValue);
Result := TMemoryStream.Create;
Result.Size := l;
at := 0;
remainLen := l;
while remainLen > 0 do
begin
if remainLen > PieceSize then
bufLen := PieceSize
else
bufLen := remainLen;
p := TMemoryStream(Result).Memory;
Move(s.fValue[at], p[at], bufLen);
Inc(at, bufLen);
Dec(remainLen, bufLen);
end;
Result.Position := 0;
end;
function TSerialize.getVariant(const keyName: rawbytestring): variant;
var
p: pbyte;
l: integer;
s: TSerialize;
begin
s := key(keyName);
l := Length(s.fValue);
Result := VarArrayCreate([0, l - 1], varByte);
p := VarArrayLock(Result);
Move(s.fValue[0], p^, l);
VarArrayUnlock(Result);
end;
function TSerialize.getWord(const keyName: rawbytestring): word;
var
s: TSerialize;
begin
s := key(keyName);
Result := pword(s.fValue)^;
end;
function TSerialize.getBytes(const keyName: rawbytestring): TBytes;
var
s: TSerialize;
begin
s := key(keyName);
Result := s.fValue;
end;
function TSerialize.getByte(const keyName: rawbytestring): byte;
var
s: TSerialize;
begin
s := key(keyName);
Result := pbyte(s.fValue)^;
end;
function TSerialize.getInt64(const keyName: rawbytestring): int64;
var
s: TSerialize;
begin
s := key(keyName);
Result := PInt64(s.fValue)^;
end;
function TSerialize.getLongWord(const keyName: rawbytestring): LongWord;
var
s: TSerialize;
begin
s := key(keyName);
Result := PLongWord(s.fValue)^;
end;
function TSerialize.getShortint(const keyName: rawbytestring): Shortint;
var
s: TSerialize;
begin
s := key(keyName);
Result := PShortint(s.fValue)^;
end;
function TSerialize.getSingle(const keyName: rawbytestring): single;
var
s: TSerialize;
begin
s := key(keyName);
Result := PSingle(s.fValue)^;
end;
function TSerialize.getSmallint(const keyName: rawbytestring): Smallint;
var
s: TSerialize;
begin
s := key(keyName);
Result := PSmallint(s.fValue)^;
end;
function TSerialize.getDateTime(const keyName: rawbytestring): TDateTime;
var
s: TSerialize;
begin
s := key(keyName);
Result := PDateTime(s.fValue)^;
end;
function TSerialize.getBool(const keyName: rawbytestring): boolean;
var
s: TSerialize;
begin
s := key(keyName);
Result := PBoolean(s.fValue)^;
end;
function TSerialize.getDouble(const keyName: rawbytestring): double;
var
s: TSerialize;
begin
s := key(keyName);
Result := PDouble(s.fValue)^;
end;
function TSerialize.getExtended(const keyName: rawbytestring): Extended;
var
s: TSerialize;
begin
s := key(keyName);
Result := PExtended(s.fValue)^;
end;
function TSerialize.getCurrency(const keyName: rawbytestring): Currency;
var
s: TSerialize;
begin
s := key(keyName);
Result := PCurrency(s.fValue)^;
end;
procedure TSerialize.setDouble(const keyName: rawbytestring; const Value: double);
var
s: TSerialize;
begin
s := key(keyName);
SetLength(s.fValue, SizeOf(double));
PDouble(s.fValue)^ := Value;
end;
procedure TSerialize.setExtended(const keyName: rawbytestring; const Value: Extended);
var
s: TSerialize;
begin
s := key(keyName);
SetLength(s.fValue, SizeOf(Extended));
PExtended(s.fValue)^ := Value;
end;
procedure TSerialize.setInt(const keyName: rawbytestring; const Value: integer);
var
s: TSerialize;
begin
s := key(keyName);
SetLength(s.fValue, SizeOf(integer));
PInteger(s.fValue)^ := Value;
end;
procedure TSerialize.setShortint(const keyName: rawbytestring; const Value: Shortint);
var
s: TSerialize;
begin
s := key(keyName);
SetLength(s.fValue, SizeOf(Shortint));
PShortint(s.fValue)^ := Value;
end;
procedure TSerialize.setSingle(const keyName: rawbytestring; const Value: single);
var
s: TSerialize;
begin
s := key(keyName);
SetLength(s.fValue, SizeOf(single));
PSingle(s.fValue)^ := Value;
end;
procedure TSerialize.setSmallint(const keyName: rawbytestring; const Value: Smallint);
var
s: TSerialize;
begin
s := key(keyName);
SetLength(s.fValue, SizeOf(Smallint));
PSmallint(s.fValue)^ := Value;
end;
procedure TSerialize.setStr(const keyName: rawbytestring; const Value: rawbytestring);
var
l: integer;
s: TSerialize;
begin
s := key(keyName);
l := Length(Value);
SetLength(s.fValue, l);
if l > 0 then
Move(PRawByteString(Value)^, s.fValue[0], l);
end;
procedure TSerialize.setStream(const keyName: rawbytestring; const Value: tstream);
var
s: TSerialize;
at, bufLen, remainLen: Integer;
p: pbyte;
begin
s := key(keyName);
SetLength(s.fValue, Value.Size);
Value.Position := 0;
at := 0;
remainLen := Value.Size;
while remainLen > 0 do
begin
if remainLen > PieceSize then
bufLen := PieceSize
else
bufLen := remainLen;
p := TMemoryStream(Value).Memory;
Move(p[at], s.fValue[at], bufLen); // value
Inc(at, bufLen);
Dec(remainLen, bufLen);
end;
end;
procedure TSerialize.setVariant(const keyName: rawbytestring; const Value: variant);
var
p: pbyte;
l: integer;
s: TSerialize;
begin
s := key(keyName);
l := VarArrayHighBound(Value, 1) - VarArrayLowBound(Value, 1) + 1;
p := VarArrayLock(Value);
SetLength(s.fValue, l);
Move(p^, s.fValue[0], l);
VarArrayUnlock(Value);
end;
procedure TSerialize.setWord(const keyName: rawbytestring; const Value: word);
var
s: TSerialize;
begin
s := key(keyName);
SetLength(s.fValue, SizeOf(word));
PWord(s.fValue)^ := Value;
end;
procedure TSerialize.setBytes(const keyName: rawbytestring; const Value: TBytes);
var
s: TSerialize;
begin
s := key(keyName);
s.fValue := Value;
end;
procedure TSerialize.setCurrency(const keyName: rawbytestring; const Value: Currency);
var
s: TSerialize;
begin
s := key(keyName);
SetLength(s.fValue, SizeOf(Currency));
pCurrency(s.fValue)^ := Value;
end;
procedure TSerialize.setByte(const keyName: rawbytestring; const Value: byte);
var
s: TSerialize;
begin
s := key(keyName);
SetLength(s.fValue, SizeOf(byte));
pbyte(s.fValue)^ := Value;
end;
procedure TSerialize.setInt64(const keyName: rawbytestring; const Value: int64);
var
s: TSerialize;
begin
s := key(keyName);
SetLength(s.fValue, SizeOf(int64));
PInt64(s.fValue)^ := Value;
end;
procedure TSerialize.setLongWord(const keyName: rawbytestring; const Value: LongWord);
var
s: TSerialize;
begin
s := key(keyName);
SetLength(s.fValue, SizeOf(LongWord));
PLongWord(s.fValue)^ := Value;
end;
procedure TSerialize.setDateTime(const keyName: rawbytestring; const Value: TDateTime);
var
s: TSerialize;
begin
s := key(keyName);
SetLength(s.fValue, SizeOf(TDateTime));
PDateTime(s.fValue)^ := Value;
end;
procedure TSerialize.setBool(const keyName: rawbytestring; const Value: boolean);
var
s: TSerialize;
begin
s := key(keyName);
SetLength(s.fValue, SizeOf(boolean));
PBoolean(s.fValue)^ := Value;
end;
procedure TSerialize.setBCD(const keyName: rawbytestring; const Value: tbcd);
var s: TSerialize;
begin
s := key(keyName);
SetLength(s.fValue, SizeOf(TBcd));
PBcd(s.fValue)^ := Value;
end;
procedure TSerialize.unMarshal(stream: TStream);
var
keyLen, valueLen, remainLen, at, bufLen: integer;
keyName: rawbytestring;
Value: TBytes;
s: TSerialize;
begin
stream.Position := 0;
while stream.Position < stream.Size do
begin
stream.Read(keyLen, SizeOf(Integer)); // key len
SetLength(keyName, keyLen);
stream.Read(PRawByteString(keyName)^, keyLen); // key
stream.Read(valueLen, SizeOf(Integer)); // value len
SetLength(Value, valueLen); // value
remainLen := valueLen;
at := 0;
while remainLen > 0 do
begin
if remainLen > PieceSize then
bufLen := PieceSize
else
bufLen := remainLen;
stream.read(Value[at], bufLen); // value
Inc(at, bufLen);
Dec(remainLen, bufLen);
end;
s := TSerialize.Create;
s.fValue := Value;
s.fKey := keyName;
fList.Add(s);
end;
end;
procedure TSerialize.unMarshal(ole: OleVariant);
var
keyLen, valueLen, at, at2, remainLen, BufLen, l: integer;
keyName: rawbytestring;
Value: TBytes;
s: TSerialize;
p: pbyte;
begin
at := 0;
l := VarArrayHighBound(ole, 1) - VarArrayLowBound(ole, 1) + 1;
p := VarArrayLock(ole);
while at < l do
begin
Move(p[at], keyLen, SizeOf(Integer)); // key len
inc(at, SizeOf(Integer));
SetLength(keyName, keyLen);
Move(p[at], PRawByteString(keyName)^, keyLen); // key
inc(at, keyLen);
Move(p[at], valueLen, SizeOf(Integer)); // value len
inc(at, SizeOf(Integer));
SetLength(Value, valueLen); // value
at2 := 0;
remainLen := valueLen;
while remainLen > 0 do
begin
if remainLen > PieceSize then
BufLen := PieceSize
else
BufLen := remainLen;
Move(p[at], Value[at2], BufLen); // value
Inc(at, BufLen);
Inc(at2, BufLen);
Dec(remainLen, BufLen);
end;
s := TSerialize.Create;
s.fValue := Value;
s.fKey := keyName;
fList.Add(s);
end;
VarArrayUnlock(ole);
end;
procedure TSerialize.unMarshal(bytes: TBytes);
var
keyLen, valueLen, at, at2, remainLen, BufLen: integer;
keyName: rawbytestring;
Value: TBytes;
s: TSerialize;
begin
at := 0;
while at < Length(bytes) do
begin
Move(bytes[at], keyLen, SizeOf(Integer)); // key len
inc(at, SizeOf(Integer));
SetLength(keyName, keyLen);
Move(bytes[at], PRawByteString(keyName)^, keyLen); // key
inc(at, keyLen);
Move(bytes[at], valueLen, SizeOf(Integer)); // value len
inc(at, SizeOf(Integer));
SetLength(Value, valueLen); // value
at2 := 0;
remainLen := valueLen;
while remainLen > 0 do
begin
if remainLen > PieceSize then
BufLen := PieceSize
else
BufLen := remainLen;
Move(bytes[at], Value[at2], BufLen); // value
Inc(at, BufLen);
Inc(at2, BufLen);
Dec(remainLen, BufLen);
end;
s := TSerialize.Create;
s.fValue := Value;
s.fKey := keyName;
fList.Add(s);
end;
end;
procedure TSerialize.unMarshal(raw: RawByteString);
var
keyLen, valueLen, at, at2, remainLen, BufLen: integer;
keyName: rawbytestring;
Value: TBytes;
s: TSerialize;
begin
at := 0;
while at < Length(raw) do
begin
if at = 0 then
at := 1;
Move(raw[at], keyLen, SizeOf(Integer)); // key len
inc(at, SizeOf(Integer));
SetLength(keyName, keyLen);
Move(raw[at], PRawByteString(keyName)^, keyLen); // key
inc(at, keyLen);
Move(raw[at], valueLen, SizeOf(Integer)); // value len
inc(at, SizeOf(Integer));
SetLength(Value, valueLen); // value
at2 := 0;
remainLen := valueLen;
while remainLen > 0 do
begin
if remainLen > PieceSize then
BufLen := PieceSize
else
BufLen := remainLen;
Move(raw[at], Value[at2], BufLen); // value
Inc(at, BufLen);
Inc(at2, BufLen);
Dec(remainLen, BufLen);
end;
s := TSerialize.Create;
s.fValue := Value;
s.fKey := keyName;
fList.Add(s);
end;
end;
procedure TSerialize.marshal(stream: TStream);
var
i: integer;
s: TSerialize;
keyLen, valueLen, bufLen, remainLen, at: integer;
begin
stream.Position := 0;
for i := 0 to fList.Count - 1 do
begin
s := TSerialize(fList[i]);
keyLen := Length(s.fKey);
stream.Write(keyLen, SizeOf(Integer)); // key len
stream.Write(prawbytestring(s.fKey)^, keyLen); // key
valueLen := Length(s.fValue); // value len
stream.Write(valueLen, SizeOf(Integer));
remainLen := valueLen;
at := 0;
while remainLen > 0 do
begin
if remainLen > PieceSize then
bufLen := PieceSize
else
bufLen := remainLen;
stream.Write(s.fValue[at], bufLen); // value
Inc(at, bufLen);
Dec(remainLen, bufLen);
end;
end;
end;
function TSerialize.marshal2: TBytes;
var
i, at, at2, l: integer;
s: TSerialize;
keyLen, valueLen, remainLen, bufLen: integer;
begin
l := 0;
for i := 0 to fList.Count - 1 do
begin
s := TSerialize(fList[i]);
keyLen := Length(s.fKey);
valueLen := Length(s.fValue);
inc(l, SizeOf(Integer) + keyLen + SizeOf(Integer) + valueLen);
end;
SetLength(Result, l);
at := 0;
for i := 0 to fList.Count - 1 do
begin
s := TSerialize(fList[i]);
keyLen := Length(s.fKey);
valueLen := Length(s.fValue);
Move(keyLen, Result[at], SizeOf(Integer)); // keyLen
inc(at, SizeOf(Integer));
Move(prawbytestring(s.fKey)^, Result[at], keyLen);
inc(at, keyLen);
Move(valueLen, Result[at], SizeOf(Integer)); // valueLen
inc(at, SizeOf(Integer));
at2 := 0;
remainLen := valueLen;
while remainLen > 0 do
begin
if remainLen > PieceSize then
bufLen := PieceSize
else
bufLen := remainLen;
Move(s.fValue[at2], Result[at], bufLen); // value
Inc(at, bufLen);
Inc(at2, bufLen);
Dec(remainLen, bufLen);
end;
end;
end;
function TSerialize.marshal5: OleVariant;
var
l, keyLen, valueLen, i, at, at2, remainLen, bufLen: Integer;
s: TSerialize;
p: pbyte;
begin
l := 0;
for i := 0 to fList.Count - 1 do
begin
s := TSerialize(fList[i]);
keyLen := Length(s.fKey);
valueLen := Length(s.fValue);
inc(l, SizeOf(Integer) + keyLen + SizeOf(Integer) + valueLen);
end;
Result := VarArrayCreate([0, l - 1], varByte);
at := 0;
p := VarArrayLock(Result);
for i := 0 to fList.Count - 1 do
begin
s := TSerialize(fList[i]);
keyLen := Length(s.fKey);
valueLen := Length(s.fValue);
Move(keyLen, p[at], SizeOf(Integer));
inc(at, SizeOf(Integer));
Move(prawbytestring(s.fKey)^, p[at], keyLen);
inc(at, keyLen);
Move(valueLen, p[at], SizeOf(Integer));
inc(at, SizeOf(Integer));
at2 := 0;
remainLen := valueLen;
while remainLen > 0 do
begin
if remainLen > PieceSize then
bufLen := PieceSize
else
bufLen := remainLen;
Move(s.fValue[at2], p[at], bufLen);
Inc(at, bufLen);
Inc(at2, bufLen);
Dec(remainLen, bufLen);
end;
end;
VarArrayUnlock(Result);
end;
function TSerialize.marshal3: RawByteString;
var
i, at, at2, bufLen, remainLen, l: integer;
s: TSerialize;
keyLen, valueLen: integer;
begin
l := 0;
for i := 0 to fList.Count - 1 do
begin
s := TSerialize(fList[i]);
keyLen := Length(s.fKey);
valueLen := Length(s.fValue);
inc(l, SizeOf(Integer) + keyLen + SizeOf(Integer) + valueLen);
end;
SetLength(Result, l);
at := 0;
for i := 0 to fList.Count - 1 do
begin
s := TSerialize(fList[i]);
keyLen := Length(s.fKey);
valueLen := Length(s.fValue);
if at = 0 then
at := 1;
Move(keyLen, Result[at], SizeOf(Integer)); // keyLen
inc(at, SizeOf(Integer));
Move(PRawByteString(s.fKey)^, Result[at], keyLen); // key
inc(at, keyLen);
Move(valueLen, Result[at], SizeOf(Integer)); // valueLen
inc(at, SizeOf(Integer));
at2 := 0;
remainLen := valueLen;
while remainLen > 0 do
begin
if remainLen > PieceSize then
bufLen := PieceSize
else
bufLen := remainLen;
Move(s.fValue[at2], Result[at], bufLen); // value
Inc(at, bufLen);
Inc(at2, bufLen);
Dec(remainLen, bufLen);
end;
end;
end;
procedure TSerialize.Clear;
var
i: integer;
begin
for i := fList.Count - 1 downto 0 do
begin
TSerialize(fList[i]).Free;
fList.Delete(i);
end;
end;
constructor TSerialize.Create;
begin
fList := TList.Create;
end;
function TSerialize.Delete(const keyName: rawbytestring): boolean;
var
i: integer;
begin
Result := False;
for i := fList.Count - 1 downto 0 do
begin
if TSerialize(fList[i]).fKey = keyName then
begin
TSerialize(fList[i]).Free;
fList.Delete(i);
Result := True;
end;
end;
end;
destructor TSerialize.Destroy;
begin
Self.Clear;
fList.Free;
inherited;
end;
function TSerialize.getCount: integer;
begin
Result := fList.Count;
end;
function TSerialize.getBCD(const keyName: rawbytestring): tbcd;
var
s: TSerialize;
begin
s := key(keyName);
Result := pbcd(s.fValue)^;
end;
end.