1994 lines
58 KiB
ObjectPascal
1994 lines
58 KiB
ObjectPascal
{******************************************************************************}
|
|
{ }
|
|
{ Library: Fundamentals 5.00 }
|
|
{ File name: flcProtoBufUtils.pas }
|
|
{ File version: 5.04 }
|
|
{ Description: Protocol Buffer utilities. }
|
|
{ }
|
|
{ Copyright: Copyright (c) 2012-2018, David J Butler }
|
|
{ All rights reserved. }
|
|
{ This file is licensed under the BSD License. }
|
|
{ See http://www.opensource.org/licenses/bsd-license.php }
|
|
{ Redistribution and use in source and binary forms, with }
|
|
{ or without modification, are permitted provided that }
|
|
{ the following conditions are met: }
|
|
{ Redistributions of source code must retain the above }
|
|
{ copyright notice, this list of conditions and the }
|
|
{ following disclaimer. }
|
|
{ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND }
|
|
{ CONTRIBUTORS "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 REGENTS 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. }
|
|
{ }
|
|
{ Github: https://github.com/fundamentalslib }
|
|
{ E-mail: fundamentals.library at gmail.com }
|
|
{ }
|
|
{ Revision history: }
|
|
{ }
|
|
{ 2012/04/14 0.01 VarInt encoding and decoding }
|
|
{ 2012/04/15 0.02 SInt32 encoding and decoding }
|
|
{ 2012/04/25 0.03 Improvements }
|
|
{ 2016/01/14 5.04 Revised for Fundamentals 5. }
|
|
{ 2018/08/13 5.05 String type changes. }
|
|
{ }
|
|
{ Supported compilers: }
|
|
{ }
|
|
{ Delphi XE7 Win32 5.04 2016/01/14 }
|
|
{ Delphi XE7 Win64 5.04 2016/01/14 }
|
|
{ }
|
|
{******************************************************************************}
|
|
|
|
{$INCLUDE flcProtoBuf.inc}
|
|
|
|
unit flcProtoBufUtils;
|
|
|
|
interface
|
|
|
|
uses
|
|
{ System }
|
|
SysUtils,
|
|
|
|
{ Fundamentals }
|
|
flcStdTypes;
|
|
|
|
|
|
|
|
{ SInt32 / SInt64 }
|
|
|
|
function pbSInt32ToUInt32(const A: Int32): Word32;
|
|
function pbUInt32ToSInt32(const A: Word32): Int32;
|
|
function pbSInt64ToUInt64(const A: Int64): UInt64;
|
|
function pbUInt64ToSInt64(const A: UInt64): Int64;
|
|
|
|
|
|
|
|
{ VarInt }
|
|
|
|
const
|
|
pbMaxVarIntSizeEnc = 10;
|
|
|
|
type
|
|
EpbVarIntError = class(Exception);
|
|
|
|
TpbVarInt = record
|
|
EncSize : Byte;
|
|
EncData : array[0..pbMaxVarIntSizeEnc - 1] of Byte;
|
|
end;
|
|
|
|
function pbVarIntEquals(const A, B: TpbVarInt): Boolean;
|
|
function pbVarIntIsZero(var A: TpbVarInt): Boolean;
|
|
|
|
procedure pbVarIntInitZero(var A: TpbVarInt);
|
|
procedure pbVarIntInitVarInt(var A: TpbVarInt; const B: TpbVarInt);
|
|
|
|
function pbVarIntInitEncBuf(var A: TpbVarInt; const Buf; const BufSize: Integer): Integer;
|
|
procedure pbVarIntInitBinBuf(var A: TpbVarInt; const Buf; const BufSize: Integer);
|
|
procedure pbVarIntInitUInt32(var A: TpbVarInt; const B: Word32);
|
|
procedure pbVarIntInitSInt32(var A: TpbVarInt; const B: Int32);
|
|
procedure pbVarIntInitUInt64(var A: TpbVarInt; const B: UInt64);
|
|
procedure pbVarIntInitInt64(var A: TpbVarInt; const B: Int64);
|
|
procedure pbVarIntInitSInt64(var A: TpbVarInt; const B: Int64);
|
|
|
|
function pbVarIntToEncBuf(const A: TpbVarInt; var Buf; const BufSize: Integer): Integer;
|
|
procedure pbVarIntToBinBuf(const A: TpbVarInt; var Buf; const BufSize: Integer);
|
|
function pbVarIntToUInt32(const A: TpbVarInt): Word32;
|
|
function pbVarIntToSInt32(const A: TpbVarInt): Int32;
|
|
function pbVarIntToUInt64(const A: TpbVarInt): UInt64;
|
|
function pbVarIntToInt64(const A: TpbVarInt): Int64;
|
|
function pbVarIntToSInt64(const A: TpbVarInt): Int64;
|
|
|
|
|
|
|
|
{ Wire type }
|
|
|
|
type
|
|
TpbWireType = (
|
|
pwtVarInt = 0,
|
|
pwt64Bit = 1,
|
|
pwtVarBytes = 2,
|
|
pwtStartGroup = 3, // deprecated
|
|
pwtEndGroup = 4, // deprecated
|
|
pwt32Bit = 5,
|
|
pwtNotUsed6 = 6,
|
|
pwtNotUsed7 = 7
|
|
);
|
|
|
|
|
|
|
|
{ Field key }
|
|
|
|
function pbFieldKeyToUInt32(const FieldNumber: Int32; const WireType: TpbWireType): Word32;
|
|
procedure pbUInt32ToFieldKey(const A: Word32; var FieldNumber: Int32; var WireType: TpbWireType);
|
|
|
|
|
|
|
|
{ Encode }
|
|
|
|
type
|
|
EpbEncodeError = class(Exception);
|
|
|
|
function pbEncodeValueVarInt(var Buf; const BufSize: Integer; const Value: TpbVarInt): Integer;
|
|
function pbEncodeValueInt32(var Buf; const BufSize: Integer; const Value: Int32): Integer;
|
|
function pbEncodeValueInt64(var Buf; const BufSize: Integer; const Value: Int64): Integer;
|
|
function pbEncodeValueUInt32(var Buf; const BufSize: Integer; const Value: Word32): Integer;
|
|
function pbEncodeValueUInt64(var Buf; const BufSize: Integer; const Value: UInt64): Integer;
|
|
function pbEncodeValueSInt32(var Buf; const BufSize: Integer; const Value: Int32): Integer;
|
|
function pbEncodeValueSInt64(var Buf; const BufSize: Integer; const Value: Int64): Integer;
|
|
function pbEncodeValueBool(var Buf; const BufSize: Integer; const Value: Boolean): Integer;
|
|
function pbEncodeValueDouble(var Buf; const BufSize: Integer; const Value: Double): Integer;
|
|
function pbEncodeValueFloat(var Buf; const BufSize: Integer; const Value: Single): Integer;
|
|
function pbEncodeValueFixed32(var Buf; const BufSize: Integer; const Value: Word32): Integer;
|
|
function pbEncodeValueFixed64(var Buf; const BufSize: Integer; const Value: UInt64): Integer;
|
|
function pbEncodeValueSFixed32(var Buf; const BufSize: Integer; const Value: Int32): Integer;
|
|
function pbEncodeValueSFixed64(var Buf; const BufSize: Integer; const Value: Int64): Integer;
|
|
function pbEncodeValueString(var Buf; const BufSize: Integer; const Value: RawByteString): Integer;
|
|
function pbEncodeValueBytes(var Buf; const BufSize: Integer; const ValueBuf; const ValueBufSize: Integer): Integer;
|
|
|
|
function pbEncodeFieldKey(var Buf; const BufSize: Integer; const FieldNumber: Int32; const WireType: TpbWireType): Integer;
|
|
function pbEncodeFieldVarBytesHdr(var Buf; const BufSize: Integer; const FieldNumber: Int32; const VarBytesSize: Integer): Integer;
|
|
|
|
function pbEncodeFieldVarInt(var Buf; const BufSize: Integer; const FieldNumber: Int32; const Value: TpbVarInt): Integer;
|
|
function pbEncodeFieldInt32(var Buf; const BufSize: Integer; const FieldNumber: Int32; const Value: Int32): Integer;
|
|
function pbEncodeFieldInt64(var Buf; const BufSize: Integer; const FieldNumber: Int32; const Value: Int64): Integer;
|
|
function pbEncodeFieldUInt32(var Buf; const BufSize: Integer; const FieldNumber: Int32; const Value: Word32): Integer;
|
|
function pbEncodeFieldUInt64(var Buf; const BufSize: Integer; const FieldNumber: Int32; const Value: UInt64): Integer;
|
|
function pbEncodeFieldSInt32(var Buf; const BufSize: Integer; const FieldNumber: Int32; const Value: Int32): Integer;
|
|
function pbEncodeFieldSInt64(var Buf; const BufSize: Integer; const FieldNumber: Int32; const Value: Int64): Integer;
|
|
function pbEncodeFieldBool(var Buf; const BufSize: Integer; const FieldNumber: Int32; const Value: Boolean): Integer;
|
|
function pbEncodeFieldDouble(var Buf; const BufSize: Integer; const FieldNumber: Int32; const Value: Double): Integer;
|
|
function pbEncodeFieldFloat(var Buf; const BufSize: Integer; const FieldNumber: Int32; const Value: Single): Integer;
|
|
function pbEncodeFieldFixed32(var Buf; const BufSize: Integer; const FieldNumber: Int32; const Value: Word32): Integer;
|
|
function pbEncodeFieldFixed64(var Buf; const BufSize: Integer; const FieldNumber: Int32; const Value: UInt64): Integer;
|
|
function pbEncodeFieldSFixed32(var Buf; const BufSize: Integer; const FieldNumber: Int32; const Value: Int32): Integer;
|
|
function pbEncodeFieldSFixed64(var Buf; const BufSize: Integer; const FieldNumber: Int32; const Value: Int64): Integer;
|
|
function pbEncodeFieldString(var Buf; const BufSize: Integer; const FieldNumber: Int32; const Value: RawByteString): Integer;
|
|
function pbEncodeFieldBytes(var Buf; const BufSize: Integer; const FieldNumber: Int32; const ValueBuf; const ValueBufSize: Integer): Integer;
|
|
|
|
|
|
|
|
{ Decode }
|
|
|
|
type
|
|
EpbDecodeError = class(Exception);
|
|
|
|
function pbDecodeValueInt32(const Buf; const BufSize: Integer; var Value: Int32): Integer;
|
|
function pbDecodeValueInt64(const Buf; const BufSize: Integer; var Value: Int64): Integer;
|
|
function pbDecodeValueUInt32(const Buf; const BufSize: Integer; var Value: Word32): Integer;
|
|
function pbDecodeValueUInt64(const Buf; const BufSize: Integer; var Value: UInt64): Integer;
|
|
function pbDecodeValueSInt32(const Buf; const BufSize: Integer; var Value: Int32): Integer;
|
|
function pbDecodeValueSInt64(const Buf; const BufSize: Integer; var Value: Int64): Integer;
|
|
function pbDecodeValueDouble(const Buf; const BufSize: Integer; var Value: Double): Integer;
|
|
function pbDecodeValueFloat(const Buf; const BufSize: Integer; var Value: Single): Integer;
|
|
function pbDecodeValueFixed32(const Buf; const BufSize: Integer; var Value: Word32): Integer;
|
|
function pbDecodeValueFixed64(const Buf; const BufSize: Integer; var Value: UInt64): Integer;
|
|
function pbDecodeValueSFixed32(const Buf; const BufSize: Integer; var Value: Int32): Integer;
|
|
function pbDecodeValueSFixed64(const Buf; const BufSize: Integer; var Value: Int64): Integer;
|
|
function pbDecodeValueBool(const Buf; const BufSize: Integer; var Value: Boolean): Integer;
|
|
function pbDecodeValueString(const Buf; const BufSize: Integer; var Value: RawByteString): Integer;
|
|
function pbDecodeValueBytes(const Buf; const BufSize: Integer; var ValueBuf; const ValueBufSize: Integer): Integer;
|
|
|
|
type
|
|
TpbProtoBufDecodeField = record
|
|
FieldNum : Int32;
|
|
WireType : TpbWireType;
|
|
WireDataPtr : Pointer;
|
|
WireDataSize : Int32;
|
|
ValueVarInt : TpbVarInt;
|
|
ValueVarBytesPtr : Pointer;
|
|
ValueVarBytesLen : Int32;
|
|
end;
|
|
PpbProtoBufDecodeField = ^TpbProtoBufDecodeField;
|
|
|
|
TpbProtoBufDecodeFieldCallbackProc =
|
|
procedure (const Field: TpbProtoBufDecodeField;
|
|
const Data: Pointer);
|
|
|
|
procedure pbDecodeProtoBuf(
|
|
const Buf; const BufSize: Integer;
|
|
const CallbackProc: TpbProtoBufDecodeFieldCallbackProc;
|
|
const CallbackData: Pointer);
|
|
|
|
procedure pbDecodeFieldInt32(const Field: TpbProtoBufDecodeField; var Value: Int32);
|
|
procedure pbDecodeFieldInt64(const Field: TpbProtoBufDecodeField; var Value: Int64);
|
|
procedure pbDecodeFieldUInt32(const Field: TpbProtoBufDecodeField; var Value: Word32);
|
|
procedure pbDecodeFieldUInt64(const Field: TpbProtoBufDecodeField; var Value: UInt64);
|
|
procedure pbDecodeFieldSInt32(const Field: TpbProtoBufDecodeField; var Value: Int32);
|
|
procedure pbDecodeFieldSInt64(const Field: TpbProtoBufDecodeField; var Value: Int64);
|
|
procedure pbDecodeFieldDouble(const Field: TpbProtoBufDecodeField; var Value: Double);
|
|
procedure pbDecodeFieldFloat(const Field: TpbProtoBufDecodeField; var Value: Single);
|
|
procedure pbDecodeFieldFixed32(const Field: TpbProtoBufDecodeField; var Value: Word32);
|
|
procedure pbDecodeFieldFixed64(const Field: TpbProtoBufDecodeField; var Value: UInt64);
|
|
procedure pbDecodeFieldSFixed32(const Field: TpbProtoBufDecodeField; var Value: Int32);
|
|
procedure pbDecodeFieldSFixed64(const Field: TpbProtoBufDecodeField; var Value: Int64);
|
|
procedure pbDecodeFieldBool(const Field: TpbProtoBufDecodeField; var Value: Boolean);
|
|
function pbDecodeFieldString(const Field: TpbProtoBufDecodeField; var Value: RawByteString): Integer;
|
|
function pbDecodeFieldBytes(const Field: TpbProtoBufDecodeField; var ValueBuf; const ValueBufSize: Integer): Integer;
|
|
|
|
|
|
|
|
{ }
|
|
{ Test cases }
|
|
{ }
|
|
{$IFDEF PROTOBUF_TEST}
|
|
procedure Test;
|
|
{$ENDIF}
|
|
|
|
|
|
|
|
implementation
|
|
|
|
|
|
|
|
{ Strings }
|
|
|
|
const
|
|
SErr_BufferTooSmall = 'Buffer too small';
|
|
SErr_Overflow = 'Overflow';
|
|
SErr_InvalidVarInt = 'Invalid VarInt';
|
|
SErr_InvalidBuffer = 'Invalid buffer';
|
|
SErr_InvalidWireType = 'Invalid wire type';
|
|
|
|
|
|
|
|
{ SInt32 }
|
|
|
|
// returns SInt32 encoded to Word32 using 'ZigZag' encoding
|
|
function pbSInt32ToUInt32(const A: Int32): Word32;
|
|
var I : Int64;
|
|
begin
|
|
if A < 0 then
|
|
begin
|
|
// use Int64 value to negate A without overflow
|
|
I := A;
|
|
I := -I;
|
|
// encode ZigZag
|
|
Result := (Word32(I) - 1) * 2 + 1
|
|
end
|
|
else
|
|
Result := Word32(A) * 2;
|
|
end;
|
|
|
|
// returns SInt32 decoded from Word32 using 'ZigZag' encoding
|
|
function pbUInt32ToSInt32(const A: Word32): Int32;
|
|
begin
|
|
if A and 1 <> 0 then
|
|
Result := -(A div 2) - 1
|
|
else
|
|
Result := A div 2;
|
|
end;
|
|
|
|
// returns SInt64 encoded to UInt64 using 'ZigZag' encoding
|
|
function pbSInt64ToUInt64(const A: Int64): UInt64;
|
|
var I : UInt64;
|
|
begin
|
|
if A < 0 then
|
|
begin
|
|
// use two's complement to negate A without overflow
|
|
I := not A;
|
|
Inc(I);
|
|
// encode ZigZag
|
|
Dec(I);
|
|
I := I * 2;
|
|
Inc(I);
|
|
Result := I;
|
|
end
|
|
else
|
|
Result := UInt64(A) * 2;
|
|
end;
|
|
|
|
// returns SInt64 decoded from UInt64 using 'ZigZag' encoding
|
|
function pbUInt64ToSInt64(const A: UInt64): Int64;
|
|
var I : Int64;
|
|
begin
|
|
if A and 1 <> 0 then
|
|
begin
|
|
I := A shr 1;
|
|
I := -I;
|
|
Dec(I);
|
|
Result := I;
|
|
end
|
|
else
|
|
begin
|
|
I := A shr 1;
|
|
Result := I;
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
{ VarInt }
|
|
|
|
// returns true if two VarInts have equal values
|
|
function pbVarIntEquals(const A, B: TpbVarInt): Boolean;
|
|
var I, L : Integer;
|
|
begin
|
|
L := A.EncSize;
|
|
Result := L = B.EncSize;
|
|
if not Result then
|
|
exit;
|
|
for I := 0 to L - 1 do
|
|
if A.EncData[I] <> B.EncData[I] then
|
|
begin
|
|
Result := False;
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
function pbVarIntIsZero(var A: TpbVarInt): Boolean;
|
|
begin
|
|
Result :=
|
|
(A.EncSize = 1) and
|
|
(A.EncData[0] = 0);
|
|
end;
|
|
|
|
// initialises VarInt to zero
|
|
procedure pbVarIntInitZero(var A: TpbVarInt);
|
|
begin
|
|
A.EncSize := 1;
|
|
A.EncData[0] := 0;
|
|
end;
|
|
|
|
// initialises VarInt from another VarInt
|
|
procedure pbVarIntInitVarInt(var A: TpbVarInt; const B: TpbVarInt);
|
|
begin
|
|
A.EncSize := B.EncSize;
|
|
A.EncData := B.EncData;
|
|
end;
|
|
|
|
// initialises VarInt from a VarInt encoded buffer
|
|
// encoded buffer may be larger than the VarInt encoded in it
|
|
// returns the size of the VarInt in the encoded buffer
|
|
function pbVarIntInitEncBuf(var A: TpbVarInt; const Buf; const BufSize: Integer): Integer;
|
|
var L, I : Integer;
|
|
P : PByte;
|
|
C : Byte;
|
|
begin
|
|
L := BufSize;
|
|
if L <= 0 then
|
|
begin
|
|
// no buffer
|
|
pbVarIntInitZero(A);
|
|
Result := 0;
|
|
exit;
|
|
end;
|
|
// copy and find size
|
|
I := 0;
|
|
P := @Buf;
|
|
while I < L do
|
|
begin
|
|
if I + 1 > pbMaxVarIntSizeEnc then
|
|
raise EpbVarIntError.Create(SErr_Overflow);
|
|
C := P^;
|
|
A.EncData[I] := C;
|
|
if C and $80 = 0 then
|
|
break;
|
|
Inc(I);
|
|
Inc(P);
|
|
end;
|
|
if I >= L then
|
|
raise EpbVarIntError.Create(SErr_InvalidBuffer);
|
|
Inc(I);
|
|
A.EncSize := I;
|
|
Result := I;
|
|
end;
|
|
|
|
// initialises VarInt from integer buffer
|
|
procedure pbVarIntInitBinBuf(var A: TpbVarInt; const Buf; const BufSize: Integer);
|
|
var L : Integer;
|
|
P : PByte;
|
|
I : Integer;
|
|
BinBuf : Word;
|
|
BinBufBits : ShortInt;
|
|
BinByte : Byte;
|
|
EncSize : Byte;
|
|
|
|
procedure EncodeFromBuffer;
|
|
var EncByte : Byte;
|
|
begin
|
|
// encode 7 bits
|
|
EncByte := Byte(BinBuf and $7F);
|
|
if EncSize < pbMaxVarIntSizeEnc then
|
|
A.EncData[EncSize] := EncByte
|
|
else
|
|
if EncByte <> 0 then
|
|
raise EpbVarIntError.Create(SErr_Overflow);
|
|
Inc(EncSize);
|
|
// remove 7 bits from buffer
|
|
BinBuf := BinBuf shr 7;
|
|
Dec(BinBufBits, 7);
|
|
end;
|
|
|
|
begin
|
|
L := BufSize;
|
|
if L <= 0 then
|
|
begin
|
|
// no buffer
|
|
pbVarIntInitZero(A);
|
|
exit;
|
|
end;
|
|
// skip most significant zero bytes
|
|
P := @Buf;
|
|
Inc(P, L - 1);
|
|
while (L > 0) and (P^ = 0) do
|
|
begin
|
|
Dec(P);
|
|
Dec(L);
|
|
end;
|
|
if L <= 0 then
|
|
begin
|
|
// all zero values
|
|
pbVarIntInitZero(A);
|
|
exit;
|
|
end;
|
|
// encode
|
|
P := @Buf;
|
|
EncSize := 0;
|
|
BinBuf := 0;
|
|
BinBufBits := 0;
|
|
for I := 0 to L - 1 do
|
|
begin
|
|
// buffer 8 bits
|
|
BinByte := P^;
|
|
BinBuf := BinBuf or (Word(BinByte) shl BinBufBits);
|
|
Inc(BinBufBits, 8);
|
|
Inc(P);
|
|
// encode 7 bits
|
|
EncodeFromBuffer;
|
|
// encode further 7 bits if available
|
|
if BinBufBits >= 7 then
|
|
EncodeFromBuffer;
|
|
end;
|
|
// encode last partial byte
|
|
if BinBufBits > 0 then
|
|
EncodeFromBuffer;
|
|
// find final encoding byte
|
|
while (EncSize > 1) and (A.EncData[EncSize - 1] = 0) do
|
|
Dec(EncSize);
|
|
A.EncSize := EncSize;
|
|
// mark non-final bytes
|
|
if EncSize > 1 then
|
|
begin
|
|
P := @A.EncData[0];
|
|
for I := 0 to EncSize - 2 do
|
|
begin
|
|
P^ := P^ or $80;
|
|
Inc(P);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
// initialises VarInt from Word32
|
|
procedure pbVarIntInitUInt32(var A: TpbVarInt; const B: Word32);
|
|
begin
|
|
if B < $80 then
|
|
begin
|
|
A.EncSize := 1;
|
|
A.EncData[0] := Byte(B);
|
|
end
|
|
else
|
|
if B < $4000 then
|
|
begin
|
|
A.EncSize := 2;
|
|
A.EncData[0] := Byte(B and $7F) or $80;
|
|
A.EncData[1] := Byte(B shr 7);
|
|
end
|
|
else
|
|
if B < $200000 then
|
|
begin
|
|
A.EncSize := 3;
|
|
A.EncData[0] := Byte(B and $7F) or $80;
|
|
A.EncData[1] := Byte((B shr 7) and $7F) or $80;
|
|
A.EncData[2] := Byte( B shr 14 );
|
|
end
|
|
else
|
|
if B < $10000000 then
|
|
begin
|
|
A.EncSize := 4;
|
|
A.EncData[0] := Byte(B and $7F) or $80;
|
|
A.EncData[1] := Byte((B shr 7) and $7F) or $80;
|
|
A.EncData[2] := Byte((B shr 14) and $7F) or $80;
|
|
A.EncData[3] := Byte( B shr 21 );
|
|
end
|
|
else
|
|
begin
|
|
A.EncSize := 5;
|
|
A.EncData[0] := Byte(B and $7F) or $80;
|
|
A.EncData[1] := Byte((B shr 7) and $7F) or $80;
|
|
A.EncData[2] := Byte((B shr 14) and $7F) or $80;
|
|
A.EncData[3] := Byte((B shr 21) and $7F) or $80;
|
|
A.EncData[4] := Byte( B shr 28 );
|
|
end;
|
|
end;
|
|
|
|
procedure pbVarIntInitSInt32(var A: TpbVarInt; const B: Int32);
|
|
begin
|
|
pbVarIntInitUInt32(A, pbSInt32ToUInt32(B));
|
|
end;
|
|
|
|
procedure pbVarIntInitUInt64(var A: TpbVarInt; const B: UInt64);
|
|
begin
|
|
pbVarIntInitBinBuf(A, B, SizeOf(B));
|
|
end;
|
|
|
|
procedure pbVarIntInitInt64(var A: TpbVarInt; const B: Int64);
|
|
begin
|
|
pbVarIntInitBinBuf(A, B, SizeOf(B));
|
|
end;
|
|
|
|
procedure pbVarIntInitSInt64(var A: TpbVarInt; const B: Int64);
|
|
begin
|
|
pbVarIntInitUInt64(A, pbSInt64ToUInt64(B));
|
|
end;
|
|
|
|
// converts VarInt to encoded buffer
|
|
// returns size of the encoded VarInt
|
|
function pbVarIntToEncBuf(const A: TpbVarInt; var Buf; const BufSize: Integer): Integer;
|
|
var L : Integer;
|
|
begin
|
|
L := A.EncSize;
|
|
if BufSize >= L then
|
|
Move(A.EncData[0], Buf, L);
|
|
Result := L;
|
|
end;
|
|
|
|
// converts VarInt to integer buffer
|
|
procedure pbVarIntToBinBuf(const A: TpbVarInt; var Buf; const BufSize: Integer);
|
|
var BinBuf : Word;
|
|
BinBufBits : ShortInt;
|
|
BinBufP : PByte;
|
|
BinBufLeft : Integer;
|
|
I : Integer;
|
|
EncByte : Byte;
|
|
EncByteFin : Boolean;
|
|
EncFin : Boolean;
|
|
|
|
procedure EncodeToBuffer;
|
|
var BinBufByte : Byte;
|
|
begin
|
|
BinBufByte := Byte(BinBuf and $FF);
|
|
if BinBufLeft <= 0 then
|
|
if BinBufByte = 0 then
|
|
exit
|
|
else
|
|
raise EpbVarIntError.Create(SErr_Overflow);
|
|
BinBufP^ := BinBufByte;
|
|
Inc(BinBufP);
|
|
Dec(BinBufLeft);
|
|
BinBuf := BinBuf shr 8;
|
|
Dec(BinBufBits, 8);
|
|
end;
|
|
|
|
begin
|
|
if BufSize <= 0 then
|
|
raise EpbVarIntError.Create(SErr_Overflow);
|
|
BinBufP := @Buf;
|
|
BinBufLeft := BufSize;
|
|
BinBuf := 0;
|
|
BinBufBits := 0;
|
|
for I := 0 to A.EncSize - 1 do
|
|
begin
|
|
// decode 7 bits from encoded buffer
|
|
EncByte := A.EncData[I];
|
|
EncFin := (I = A.EncSize - 1);
|
|
EncByteFin := (EncByte and $80 = 0);
|
|
if (EncFin and not EncByteFin) or
|
|
(not EncFin and EncByteFin) then
|
|
raise EpbVarIntError.Create(SErr_InvalidVarInt);
|
|
BinBuf := BinBuf or (Word(EncByte and $7F) shl BinBufBits);
|
|
Inc(BinBufBits, 7);
|
|
// encode 8 bits to binary buffer if available
|
|
if BinBufBits >= 8 then
|
|
EncodeToBuffer;
|
|
end;
|
|
// encode final partial byte
|
|
if BinBufBits > 0 then
|
|
EncodeToBuffer;
|
|
// fill rest of binary buffer with zero
|
|
while BinBufLeft > 0 do
|
|
begin
|
|
BinBufP^ := 0;
|
|
Inc(BinBufP);
|
|
Dec(BinBufLeft);
|
|
end;
|
|
end;
|
|
|
|
// returns VarInt value as Word32
|
|
function pbVarIntToUInt32(const A: TpbVarInt): Word32;
|
|
var B : Word32;
|
|
I : Byte;
|
|
EncByte : Byte;
|
|
begin
|
|
Assert(A.EncSize > 0);
|
|
Assert(A.EncSize <= pbMaxVarIntSizeEnc);
|
|
// decode
|
|
B := 0;
|
|
I := 0;
|
|
while I < A.EncSize do
|
|
begin
|
|
EncByte := A.EncData[I];
|
|
if I = 4 then
|
|
if EncByte and $F0 <> 0 then
|
|
raise EpbVarIntError.Create(SErr_Overflow);
|
|
B := B or (Word32(EncByte and $7F) shl (I * 7));
|
|
Inc(I);
|
|
if EncByte and $80 = 0 then // final byte marker
|
|
begin
|
|
if I < A.EncSize then // final byte marker before final byte reached
|
|
raise EpbVarIntError.Create(SErr_InvalidVarInt);
|
|
// finished
|
|
Result := B;
|
|
exit;
|
|
end;
|
|
end;
|
|
// final byte reached without final byte marker
|
|
raise EpbVarIntError.Create(SErr_InvalidVarInt);
|
|
end;
|
|
|
|
function pbVarIntToSInt32(const A: TpbVarInt): Int32;
|
|
begin
|
|
Result := pbUInt32ToSInt32(pbVarIntToUInt32(A));
|
|
end;
|
|
|
|
function pbVarIntToUInt64(const A: TpbVarInt): UInt64;
|
|
begin
|
|
pbVarIntToBinBuf(A, Result, SizeOf(Result));
|
|
end;
|
|
|
|
function pbVarIntToInt64(const A: TpbVarInt): Int64;
|
|
begin
|
|
pbVarIntToBinBuf(A, Result, SizeOf(Result));
|
|
end;
|
|
|
|
function pbVarIntToSInt64(const A: TpbVarInt): Int64;
|
|
begin
|
|
Result := pbUInt64ToSInt64(pbVarIntToUInt64(A));
|
|
end;
|
|
|
|
|
|
|
|
{ Field key }
|
|
|
|
function pbFieldKeyToUInt32(const FieldNumber: Int32; const WireType: TpbWireType): Word32;
|
|
begin
|
|
Result := Ord(WireType) or (FieldNumber shl 3);
|
|
end;
|
|
|
|
procedure pbUInt32ToFieldKey(const A: Word32; var FieldNumber: Int32; var WireType: TpbWireType);
|
|
begin
|
|
WireType := TpbWireType(A and 7);
|
|
FieldNumber := A shr 3;
|
|
end;
|
|
|
|
|
|
|
|
{ Encode }
|
|
|
|
function pbEncodeValueVarInt(var Buf; const BufSize: Integer; const Value: TpbVarInt): Integer;
|
|
begin
|
|
Result := pbVarIntToEncBuf(Value, Buf, BufSize);
|
|
end;
|
|
|
|
function pbEncodeValueInt32(var Buf; const BufSize: Integer; const Value: Int32): Integer;
|
|
var
|
|
A : TpbVarInt;
|
|
begin
|
|
pbVarIntInitUInt32(A, Word32(Value));
|
|
Result := pbVarIntToEncBuf(A, Buf, BufSize);
|
|
end;
|
|
|
|
function pbEncodeValueInt64(var Buf; const BufSize: Integer; const Value: Int64): Integer;
|
|
var
|
|
A : TpbVarInt;
|
|
begin
|
|
pbVarIntInitBinBuf(A, Value, SizeOf(Value));
|
|
Result := pbVarIntToEncBuf(A, Buf, BufSize);
|
|
end;
|
|
|
|
function pbEncodeValueUInt32(var Buf; const BufSize: Integer; const Value: Word32): Integer;
|
|
var
|
|
A : TpbVarInt;
|
|
begin
|
|
pbVarIntInitUInt32(A, Value);
|
|
Result := pbVarIntToEncBuf(A, Buf, BufSize);
|
|
end;
|
|
|
|
function pbEncodeValueUInt64(var Buf; const BufSize: Integer; const Value: UInt64): Integer;
|
|
var
|
|
A : TpbVarInt;
|
|
begin
|
|
pbVarIntInitBinBuf(A, Value, SizeOf(Value));
|
|
Result := pbVarIntToEncBuf(A, Buf, BufSize);
|
|
end;
|
|
|
|
function pbEncodeValueSInt32(var Buf; const BufSize: Integer; const Value: Int32): Integer;
|
|
var
|
|
A : TpbVarInt;
|
|
begin
|
|
pbVarIntInitSInt32(A, Value);
|
|
Result := pbVarIntToEncBuf(A, Buf, BufSize);
|
|
end;
|
|
|
|
function pbEncodeValueSInt64(var Buf; const BufSize: Integer; const Value: Int64): Integer;
|
|
var
|
|
A : TpbVarInt;
|
|
begin
|
|
pbVarIntInitSInt64(A, Value);
|
|
Result := pbVarIntToEncBuf(A, Buf, BufSize);
|
|
end;
|
|
|
|
function pbEncodeValueBool(var Buf; const BufSize: Integer; const Value: Boolean): Integer;
|
|
var
|
|
A : TpbVarInt;
|
|
begin
|
|
pbVarIntInitUInt32(A, Ord(Value));
|
|
Result := pbVarIntToEncBuf(A, Buf, BufSize);
|
|
end;
|
|
|
|
function pbEncodeValueDouble(var Buf; const BufSize: Integer; const Value: Double): Integer;
|
|
begin
|
|
if BufSize >= SizeOf(Value) then
|
|
PDouble(@Buf)^ := Value;
|
|
Result := SizeOf(Value);
|
|
end;
|
|
|
|
function pbEncodeValueFloat(var Buf; const BufSize: Integer; const Value: Single): Integer;
|
|
begin
|
|
if BufSize >= SizeOf(Value) then
|
|
PSingle(@Buf)^ := Value;
|
|
Result := SizeOf(Value);
|
|
end;
|
|
|
|
function pbEncodeValueFixed32(var Buf; const BufSize: Integer; const Value: Word32): Integer;
|
|
begin
|
|
if BufSize >= SizeOf(Value) then
|
|
PWord32(@Buf)^ := Value;
|
|
Result := SizeOf(Value);
|
|
end;
|
|
|
|
function pbEncodeValueFixed64(var Buf; const BufSize: Integer; const Value: UInt64): Integer;
|
|
begin
|
|
if BufSize >= SizeOf(Value) then
|
|
PUInt64(@Buf)^ := Value;
|
|
Result := SizeOf(Value);
|
|
end;
|
|
|
|
function pbEncodeValueSFixed32(var Buf; const BufSize: Integer; const Value: Int32): Integer;
|
|
begin
|
|
if BufSize >= SizeOf(Value) then
|
|
PInt32(@Buf)^ := Value;
|
|
Result := SizeOf(Value);
|
|
end;
|
|
|
|
function pbEncodeValueSFixed64(var Buf; const BufSize: Integer; const Value: Int64): Integer;
|
|
begin
|
|
if BufSize >= SizeOf(Value) then
|
|
PInt64(@Buf)^ := Value;
|
|
Result := SizeOf(Value);
|
|
end;
|
|
|
|
function pbEncodeValueString(var Buf; const BufSize: Integer; const Value: RawByteString): Integer;
|
|
var
|
|
P : PByte;
|
|
L, N, J : Integer;
|
|
A : TpbVarInt;
|
|
begin
|
|
P := @Buf;
|
|
L := BufSize;
|
|
// string length as VarInt
|
|
N := Length(Value);
|
|
pbVarIntInitUInt32(A, Word32(N));
|
|
J := pbVarIntToEncBuf(A, P^, L);
|
|
Inc(P, J);
|
|
Dec(L, J);
|
|
// string content
|
|
if N > 0 then
|
|
begin
|
|
if L >= N then
|
|
Move(Pointer(Value)^, P^, N);
|
|
Dec(L, N);
|
|
end;
|
|
Result := BufSize - L;
|
|
end;
|
|
|
|
function pbEncodeValueBytes(var Buf; const BufSize: Integer; const ValueBuf; const ValueBufSize: Integer): Integer;
|
|
var
|
|
P : PByte;
|
|
L, N, J : Integer;
|
|
A : TpbVarInt;
|
|
begin
|
|
P := @Buf;
|
|
L := BufSize;
|
|
// buffer size as VarInt
|
|
N := ValueBufSize;
|
|
pbVarIntInitUInt32(A, Word32(N));
|
|
J := pbVarIntToEncBuf(A, P^, L);
|
|
Inc(P, J);
|
|
Dec(L, J);
|
|
// buffer content
|
|
if N > 0 then
|
|
begin
|
|
if L >= N then
|
|
Move(ValueBuf, P^, N);
|
|
Dec(L, N);
|
|
end;
|
|
Result := BufSize - L;
|
|
end;
|
|
|
|
function pbEncodeFieldKey(var Buf; const BufSize: Integer;
|
|
const FieldNumber: Int32; const WireType: TpbWireType): Integer;
|
|
var
|
|
FieldKey : Word32;
|
|
A : TpbVarInt;
|
|
begin
|
|
FieldKey := pbFieldKeyToUInt32(FieldNumber, WireType);
|
|
pbVarIntInitUInt32(A, FieldKey);
|
|
Result := pbVarIntToEncBuf(A, Buf, BufSize);
|
|
end;
|
|
|
|
function pbEncodeFieldVarBytesHdr(var Buf; const BufSize: Integer;
|
|
const FieldNumber: Int32; const VarBytesSize: Integer): Integer;
|
|
var
|
|
P : PByte;
|
|
L : Integer;
|
|
I : Integer;
|
|
A : TpbVarInt;
|
|
begin
|
|
if VarBytesSize < 0 then
|
|
raise EpbEncodeError.Create(SErr_InvalidBuffer);
|
|
P := @Buf;
|
|
L := BufSize;
|
|
I := pbEncodeFieldKey(P^, L, FieldNumber, pwtVarBytes);
|
|
Dec(L, I);
|
|
Inc(P, I);
|
|
pbVarIntInitUInt32(A, Word32(VarBytesSize));
|
|
I := pbVarIntToEncBuf(A, P^, L);
|
|
Dec(L, I);
|
|
Result := BufSize - L;
|
|
end;
|
|
|
|
function pbEncodeFieldVarInt(var Buf; const BufSize: Integer;
|
|
const FieldNumber: Int32; const Value: TpbVarInt): Integer;
|
|
var
|
|
P : PByte;
|
|
L : Integer;
|
|
I : Integer;
|
|
begin
|
|
P := @Buf;
|
|
L := BufSize;
|
|
I := pbEncodeFieldKey(P^, L, FieldNumber, pwtVarInt);
|
|
Inc(P, I);
|
|
Dec(L, I);
|
|
I := pbVarIntToEncBuf(Value, P^, L);
|
|
Dec(L, I);
|
|
Result := BufSize - L;
|
|
end;
|
|
|
|
function pbEncodeFieldInt32(var Buf; const BufSize: Integer;
|
|
const FieldNumber: Int32; const Value: Int32): Integer;
|
|
var
|
|
A : TpbVarInt;
|
|
begin
|
|
pbVarIntInitUInt32(A, Word32(Value));
|
|
Result := pbEncodeFieldVarInt(Buf, BufSize, FieldNumber, A);
|
|
end;
|
|
|
|
function pbEncodeFieldInt64(var Buf; const BufSize: Integer;
|
|
const FieldNumber: Int32; const Value: Int64): Integer;
|
|
var
|
|
A : TpbVarInt;
|
|
begin
|
|
pbVarIntInitBinBuf(A, Value, SizeOf(Value));
|
|
Result := pbEncodeFieldVarInt(Buf, BufSize, FieldNumber, A);
|
|
end;
|
|
|
|
function pbEncodeFieldUInt32(var Buf; const BufSize: Integer;
|
|
const FieldNumber: Int32; const Value: Word32): Integer;
|
|
var
|
|
A : TpbVarInt;
|
|
begin
|
|
pbVarIntInitUInt32(A, Value);
|
|
Result := pbEncodeFieldVarInt(Buf, BufSize, FieldNumber, A);
|
|
end;
|
|
|
|
function pbEncodeFieldUInt64(var Buf; const BufSize: Integer;
|
|
const FieldNumber: Int32; const Value: UInt64): Integer;
|
|
var
|
|
A : TpbVarInt;
|
|
begin
|
|
pbVarIntInitBinBuf(A, Value, SizeOf(Value));
|
|
Result := pbEncodeFieldVarInt(Buf, BufSize, FieldNumber, A);
|
|
end;
|
|
|
|
function pbEncodeFieldSInt32(var Buf; const BufSize: Integer;
|
|
const FieldNumber: Int32; const Value: Int32): Integer;
|
|
var
|
|
A : TpbVarInt;
|
|
begin
|
|
pbVarIntInitSInt32(A, Value);
|
|
Result := pbEncodeFieldVarInt(Buf, BufSize, FieldNumber, A);
|
|
end;
|
|
|
|
function pbEncodeFieldSInt64(var Buf; const BufSize: Integer;
|
|
const FieldNumber: Int32; const Value: Int64): Integer;
|
|
var
|
|
A : TpbVarInt;
|
|
begin
|
|
pbVarIntInitSInt64(A, Value);
|
|
Result := pbEncodeFieldVarInt(Buf, BufSize, FieldNumber, A);
|
|
end;
|
|
|
|
function pbEncodeFieldBool(var Buf; const BufSize: Integer;
|
|
const FieldNumber: Int32; const Value: Boolean): Integer;
|
|
var
|
|
A : TpbVarInt;
|
|
begin
|
|
pbVarIntInitUInt32(A, Ord(Value));
|
|
Result := pbEncodeFieldVarInt(Buf, BufSize, FieldNumber, A);
|
|
end;
|
|
|
|
function pbEncodeFieldDouble(var Buf; const BufSize: Integer;
|
|
const FieldNumber: Int32; const Value: Double): Integer;
|
|
var
|
|
P : PByte;
|
|
L : Integer;
|
|
I : Integer;
|
|
begin
|
|
P := @Buf;
|
|
L := BufSize;
|
|
I := pbEncodeFieldKey(P^, L, FieldNumber, pwt64Bit);
|
|
Inc(P, I);
|
|
Dec(L, I);
|
|
I := pbEncodeValueDouble(P^, L, Value);
|
|
Dec(L, I);
|
|
Result := BufSize - L;
|
|
end;
|
|
|
|
function pbEncodeFieldFloat(var Buf; const BufSize: Integer;
|
|
const FieldNumber: Int32; const Value: Single): Integer;
|
|
var
|
|
P : PByte;
|
|
L : Integer;
|
|
I : Integer;
|
|
begin
|
|
P := @Buf;
|
|
L := BufSize;
|
|
I := pbEncodeFieldKey(P^, L, FieldNumber, pwt32Bit);
|
|
Inc(P, I);
|
|
Dec(L, I);
|
|
I := pbEncodeValueFloat(P^, L, Value);
|
|
Dec(L, I);
|
|
Result := BufSize - L;
|
|
end;
|
|
|
|
function pbEncodeFieldFixed32(var Buf; const BufSize: Integer;
|
|
const FieldNumber: Int32; const Value: Word32): Integer;
|
|
var
|
|
P : PByte;
|
|
L : Integer;
|
|
I : Integer;
|
|
begin
|
|
P := @Buf;
|
|
L := BufSize;
|
|
I := pbEncodeFieldKey(P^, L, FieldNumber, pwt32Bit);
|
|
Inc(P, I);
|
|
Dec(L, I);
|
|
I := pbEncodeValueFixed32(P^, L, Value);
|
|
Dec(L, I);
|
|
Result := BufSize - L;
|
|
end;
|
|
|
|
function pbEncodeFieldFixed64(var Buf; const BufSize: Integer;
|
|
const FieldNumber: Int32; const Value: UInt64): Integer;
|
|
var
|
|
P : PByte;
|
|
L : Integer;
|
|
I : Integer;
|
|
begin
|
|
P := @Buf;
|
|
L := BufSize;
|
|
I := pbEncodeFieldKey(P^, L, FieldNumber, pwt64Bit);
|
|
Inc(P, I);
|
|
Dec(L, I);
|
|
I := pbEncodeValueFixed64(P^, L, Value);
|
|
Dec(L, I);
|
|
Result := BufSize - L;
|
|
end;
|
|
|
|
function pbEncodeFieldSFixed32(var Buf; const BufSize: Integer;
|
|
const FieldNumber: Int32; const Value: Int32): Integer;
|
|
var
|
|
P : PByte;
|
|
L : Integer;
|
|
I : Integer;
|
|
begin
|
|
P := @Buf;
|
|
L := BufSize;
|
|
I := pbEncodeFieldKey(P^, L, FieldNumber, pwt32Bit);
|
|
Inc(P, I);
|
|
Dec(L, I);
|
|
I := pbEncodeValueSFixed32(P^, L, Value);
|
|
Dec(L, I);
|
|
Result := BufSize - L;
|
|
end;
|
|
|
|
function pbEncodeFieldSFixed64(var Buf; const BufSize: Integer;
|
|
const FieldNumber: Int32; const Value: Int64): Integer;
|
|
var
|
|
P : PByte;
|
|
L : Integer;
|
|
I : Integer;
|
|
begin
|
|
P := @Buf;
|
|
L := BufSize;
|
|
I := pbEncodeFieldKey(P^, L, FieldNumber, pwt64Bit);
|
|
Inc(P, I);
|
|
Dec(L, I);
|
|
I := pbEncodeValueSFixed64(P^, L, Value);
|
|
Dec(L, I);
|
|
Result := BufSize - L;
|
|
end;
|
|
|
|
function pbEncodeFieldString(var Buf; const BufSize: Integer;
|
|
const FieldNumber: Int32; const Value: RawByteString): Integer;
|
|
var
|
|
P : PByte;
|
|
L : Integer;
|
|
I : Integer;
|
|
begin
|
|
P := @Buf;
|
|
L := BufSize;
|
|
I := pbEncodeFieldKey(P^, L, FieldNumber, pwtVarBytes);
|
|
Inc(P, I);
|
|
Dec(L, I);
|
|
I := pbEncodeValueString(P^, L, Value);
|
|
Dec(L, I);
|
|
Result := BufSize - L;
|
|
end;
|
|
|
|
function pbEncodeFieldBytes(var Buf; const BufSize: Integer;
|
|
const FieldNumber: Int32; const ValueBuf; const ValueBufSize: Integer): Integer;
|
|
var
|
|
P : PByte;
|
|
L : Integer;
|
|
I : Integer;
|
|
begin
|
|
if ValueBufSize < 0 then
|
|
raise EpbEncodeError.Create(SErr_InvalidBuffer);
|
|
P := @Buf;
|
|
L := BufSize;
|
|
I := pbEncodeFieldKey(P^, L, FieldNumber, pwtVarBytes);
|
|
Inc(P, I);
|
|
Dec(L, I);
|
|
I := pbEncodeValueBytes(P^, L, ValueBuf, ValueBufSize);
|
|
Dec(L, I);
|
|
Result := BufSize - L;
|
|
end;
|
|
|
|
|
|
|
|
{ Decode }
|
|
|
|
function pbDecodeValueInt32(const Buf; const BufSize: Integer; var Value: Int32): Integer;
|
|
var
|
|
A : TpbVarInt;
|
|
begin
|
|
Result := pbVarIntInitEncBuf(A, Buf, BufSize);
|
|
pbVarIntToBinBuf(A, Value, SizeOf(Value));
|
|
end;
|
|
|
|
function pbDecodeValueInt64(const Buf; const BufSize: Integer; var Value: Int64): Integer;
|
|
var
|
|
A : TpbVarInt;
|
|
begin
|
|
Result := pbVarIntInitEncBuf(A, Buf, BufSize);
|
|
pbVarIntToBinBuf(A, Value, SizeOf(Value));
|
|
end;
|
|
|
|
function pbDecodeValueUInt32(const Buf; const BufSize: Integer; var Value: Word32): Integer;
|
|
var
|
|
A : TpbVarInt;
|
|
begin
|
|
Result := pbVarIntInitEncBuf(A, Buf, BufSize);
|
|
pbVarIntToBinBuf(A, Value, SizeOf(Value));
|
|
end;
|
|
|
|
function pbDecodeValueUInt64(const Buf; const BufSize: Integer; var Value: UInt64): Integer;
|
|
var
|
|
A : TpbVarInt;
|
|
begin
|
|
Result := pbVarIntInitEncBuf(A, Buf, BufSize);
|
|
pbVarIntToBinBuf(A, Value, SizeOf(Value));
|
|
end;
|
|
|
|
function pbDecodeValueSInt32(const Buf; const BufSize: Integer; var Value: Int32): Integer;
|
|
var
|
|
A : TpbVarInt;
|
|
begin
|
|
Result := pbVarIntInitEncBuf(A, Buf, BufSize);
|
|
Value := pbVarIntToSInt32(A);
|
|
end;
|
|
|
|
function pbDecodeValueSInt64(const Buf; const BufSize: Integer; var Value: Int64): Integer;
|
|
var
|
|
A : TpbVarInt;
|
|
begin
|
|
Result := pbVarIntInitEncBuf(A, Buf, BufSize);
|
|
Value := pbVarIntToSInt64(A);
|
|
end;
|
|
|
|
function pbDecodeValueDouble(const Buf; const BufSize: Integer; var Value: Double): Integer;
|
|
begin
|
|
if BufSize < SizeOf(Value) then
|
|
raise EpbDecodeError.Create(SErr_InvalidBuffer);
|
|
Value := PDouble(@Buf)^;
|
|
Result := SizeOf(Value);
|
|
end;
|
|
|
|
function pbDecodeValueFloat(const Buf; const BufSize: Integer; var Value: Single): Integer;
|
|
begin
|
|
if BufSize < SizeOf(Value) then
|
|
raise EpbDecodeError.Create(SErr_InvalidBuffer);
|
|
Value := PSingle(@Buf)^;
|
|
Result := SizeOf(Value);
|
|
end;
|
|
|
|
function pbDecodeValueFixed32(const Buf; const BufSize: Integer; var Value: Word32): Integer;
|
|
begin
|
|
if BufSize < SizeOf(Value) then
|
|
raise EpbDecodeError.Create(SErr_InvalidBuffer);
|
|
Value := PWord32(@Buf)^;
|
|
Result := SizeOf(Value);
|
|
end;
|
|
|
|
function pbDecodeValueFixed64(const Buf; const BufSize: Integer; var Value: UInt64): Integer;
|
|
begin
|
|
if BufSize < SizeOf(Value) then
|
|
raise EpbDecodeError.Create(SErr_InvalidBuffer);
|
|
Value := PUInt64(@Buf)^;
|
|
Result := SizeOf(Value);
|
|
end;
|
|
|
|
function pbDecodeValueSFixed32(const Buf; const BufSize: Integer; var Value: Int32): Integer;
|
|
begin
|
|
if BufSize < SizeOf(Value) then
|
|
raise EpbDecodeError.Create(SErr_InvalidBuffer);
|
|
Value := PInt32(@Buf)^;
|
|
Result := SizeOf(Value);
|
|
end;
|
|
|
|
function pbDecodeValueSFixed64(const Buf; const BufSize: Integer; var Value: Int64): Integer;
|
|
begin
|
|
if BufSize < SizeOf(Value) then
|
|
raise EpbDecodeError.Create(SErr_InvalidBuffer);
|
|
Value := PInt64(@Buf)^;
|
|
Result := SizeOf(Value);
|
|
end;
|
|
|
|
function pbDecodeValueBool(const Buf; const BufSize: Integer; var Value: Boolean): Integer;
|
|
var
|
|
A : TpbVarInt;
|
|
begin
|
|
Result := pbVarIntInitEncBuf(A, Buf, BufSize);
|
|
Value := not pbVarIntIsZero(A);
|
|
end;
|
|
|
|
function pbDecodeValueString(const Buf; const BufSize: Integer; var Value: RawByteString): Integer;
|
|
var
|
|
P : PByte;
|
|
L, I, N : Integer;
|
|
S : RawByteString;
|
|
begin
|
|
P := @Buf;
|
|
L := BufSize;
|
|
I := pbDecodeValueInt32(P^, L, N);
|
|
Dec(L, I);
|
|
Inc(P, I);
|
|
if L < N then
|
|
raise EpbDecodeError.Create(SErr_InvalidBuffer);
|
|
SetLength(S, N);
|
|
if N > 0 then
|
|
begin
|
|
Move(P^, Pointer(S)^, N);
|
|
Dec(L, N);
|
|
end;
|
|
Value := S;
|
|
Result:= BufSize - L;
|
|
end;
|
|
|
|
function pbDecodeValueBytes(const Buf; const BufSize: Integer; var ValueBuf; const ValueBufSize: Integer): Integer;
|
|
var
|
|
P : PByte;
|
|
L, I, N : Integer;
|
|
begin
|
|
P := @Buf;
|
|
L := BufSize;
|
|
I := pbDecodeValueInt32(P^, L, N);
|
|
Dec(L, I);
|
|
Inc(P, I);
|
|
if L < N then
|
|
raise EpbDecodeError.Create(SErr_InvalidBuffer);
|
|
if N > 0 then
|
|
begin
|
|
if ValueBufSize < N then
|
|
raise EpbDecodeError.Create(SErr_InvalidBuffer);
|
|
Move(P^, ValueBuf, N);
|
|
Dec(L, N);
|
|
end;
|
|
Result:= BufSize - L;
|
|
end;
|
|
|
|
procedure pbDecodeProtoBuf(
|
|
const Buf; const BufSize: Integer;
|
|
const CallbackProc: TpbProtoBufDecodeFieldCallbackProc;
|
|
const CallbackData: Pointer);
|
|
var
|
|
P : PByte;
|
|
L : Integer;
|
|
I : Integer;
|
|
A : TpbVarInt;
|
|
Q : PByte;
|
|
WireSize : Integer;
|
|
Key32 : Word32;
|
|
Field : TpbProtoBufDecodeField;
|
|
begin
|
|
P := @Buf;
|
|
L := BufSize;
|
|
while L > 0 do
|
|
begin
|
|
// decode field key
|
|
I := pbVarIntInitEncBuf(A, P^, L);
|
|
Assert(I > 0);
|
|
Inc(P, I);
|
|
Dec(L, I);
|
|
Key32 := pbVarIntToUInt32(A);
|
|
pbUInt32ToFieldKey(Key32, Field.FieldNum, Field.WireType);
|
|
// decode wire data
|
|
Field.WireDataPtr := P;
|
|
case Field.WireType of
|
|
pwt32Bit : WireSize := 4;
|
|
pwt64Bit : WireSize := 8;
|
|
pwtVarInt : WireSize := pbVarIntInitEncBuf(Field.ValueVarInt, P^, L);
|
|
pwtVarBytes :
|
|
begin
|
|
// VarBytes size
|
|
I := pbVarIntInitEncBuf(A, P^, L);
|
|
Field.ValueVarBytesLen := pbVarIntToUInt32(A);
|
|
// VarBytes data
|
|
Q := P;
|
|
Inc(Q, I);
|
|
Field.ValueVarBytesPtr := Q;
|
|
// wire size
|
|
WireSize := I + Field.ValueVarBytesLen;
|
|
end;
|
|
else
|
|
raise EpbDecodeError.Create(SErr_InvalidBuffer); // unrecognised wire type
|
|
end;
|
|
Field.WireDataSize := WireSize;
|
|
if WireSize > L then
|
|
raise EpbDecodeError.Create(SErr_InvalidBuffer); // incomplete/bad buffer
|
|
Inc(P, WireSize);
|
|
Dec(L, WireSize);
|
|
// field callback
|
|
if Assigned(CallbackProc) then
|
|
CallbackProc(Field, CallbackData);
|
|
end;
|
|
end;
|
|
|
|
procedure pbDecodeFieldInt32(const Field: TpbProtoBufDecodeField; var Value: Int32);
|
|
begin
|
|
case Field.WireType of
|
|
pwt32Bit : Value := PInt32(Field.WireDataPtr)^;
|
|
pwtVarInt : pbVarIntToBinBuf(Field.ValueVarInt, Value, SizeOf(Value));
|
|
else
|
|
raise EpbDecodeError.Create(SErr_InvalidWireType);
|
|
end;
|
|
end;
|
|
|
|
procedure pbDecodeFieldInt64(const Field: TpbProtoBufDecodeField; var Value: Int64);
|
|
begin
|
|
case Field.WireType of
|
|
pwt32Bit : Value := PInt32(Field.WireDataPtr)^;
|
|
pwt64Bit : Value := PInt64(Field.WireDataPtr)^;
|
|
pwtVarInt : pbVarIntToBinBuf(Field.ValueVarInt, Value, SizeOf(Value));
|
|
else
|
|
raise EpbDecodeError.Create(SErr_InvalidWireType);
|
|
end;
|
|
end;
|
|
|
|
procedure pbDecodeFieldUInt32(const Field: TpbProtoBufDecodeField; var Value: Word32);
|
|
begin
|
|
case Field.WireType of
|
|
pwt32Bit : Value := PWord32(Field.WireDataPtr)^;
|
|
pwtVarInt : Value := pbVarIntToUInt32(Field.ValueVarInt);
|
|
else
|
|
raise EpbDecodeError.Create(SErr_InvalidWireType);
|
|
end;
|
|
end;
|
|
|
|
procedure pbDecodeFieldUInt64(const Field: TpbProtoBufDecodeField; var Value: UInt64);
|
|
begin
|
|
case Field.WireType of
|
|
pwt32Bit : Value := PWord32(Field.WireDataPtr)^;
|
|
pwt64Bit : Value := PUInt64(Field.WireDataPtr)^;
|
|
pwtVarInt : pbVarIntToBinBuf(Field.ValueVarInt, Value, SizeOf(Value));
|
|
else
|
|
raise EpbDecodeError.Create(SErr_InvalidWireType);
|
|
end;
|
|
end;
|
|
|
|
procedure pbDecodeFieldSInt32(const Field: TpbProtoBufDecodeField; var Value: Int32);
|
|
begin
|
|
case Field.WireType of
|
|
pwt32Bit : Value := PInt32(Field.WireDataPtr)^;
|
|
pwtVarInt : Value := pbVarIntToSInt32(Field.ValueVarInt);
|
|
else
|
|
raise EpbDecodeError.Create(SErr_InvalidWireType);
|
|
end;
|
|
end;
|
|
|
|
procedure pbDecodeFieldSInt64(const Field: TpbProtoBufDecodeField; var Value: Int64);
|
|
begin
|
|
case Field.WireType of
|
|
pwt32Bit : Value := PInt32(Field.WireDataPtr)^;
|
|
pwt64Bit : Value := PInt64(Field.WireDataPtr)^;
|
|
pwtVarInt : Value := pbVarIntToSInt64(Field.ValueVarInt);
|
|
else
|
|
raise EpbDecodeError.Create(SErr_InvalidWireType);
|
|
end;
|
|
end;
|
|
|
|
procedure pbDecodeFieldDouble(const Field: TpbProtoBufDecodeField; var Value: Double);
|
|
begin
|
|
case Field.WireType of
|
|
pwt32Bit : Value := PSingle(Field.WireDataPtr)^;
|
|
pwt64Bit : Value := PDouble(Field.WireDataPtr)^;
|
|
else
|
|
raise EpbDecodeError.Create(SErr_InvalidWireType);
|
|
end;
|
|
end;
|
|
|
|
procedure pbDecodeFieldFloat(const Field: TpbProtoBufDecodeField; var Value: Single);
|
|
begin
|
|
case Field.WireType of
|
|
pwt32Bit : Value := PSingle(Field.WireDataPtr)^;
|
|
else
|
|
raise EpbDecodeError.Create(SErr_InvalidWireType);
|
|
end;
|
|
end;
|
|
|
|
procedure pbDecodeFieldFixed32(const Field: TpbProtoBufDecodeField; var Value: Word32);
|
|
begin
|
|
case Field.WireType of
|
|
pwt32Bit : Value := PWord32(Field.WireDataPtr)^;
|
|
pwtVarInt : Value := pbVarIntToUInt32(Field.ValueVarInt);
|
|
else
|
|
raise EpbDecodeError.Create(SErr_InvalidWireType);
|
|
end;
|
|
end;
|
|
|
|
procedure pbDecodeFieldFixed64(const Field: TpbProtoBufDecodeField; var Value: UInt64);
|
|
begin
|
|
case Field.WireType of
|
|
pwt32Bit : Value := PWord32(Field.WireDataPtr)^;
|
|
pwt64Bit : Value := PUInt64(Field.WireDataPtr)^;
|
|
else
|
|
raise EpbDecodeError.Create(SErr_InvalidWireType);
|
|
end;
|
|
end;
|
|
|
|
procedure pbDecodeFieldSFixed32(const Field: TpbProtoBufDecodeField; var Value: Int32);
|
|
begin
|
|
case Field.WireType of
|
|
pwt32Bit : Value := PInt32(Field.WireDataPtr)^;
|
|
else
|
|
raise EpbDecodeError.Create(SErr_InvalidWireType);
|
|
end;
|
|
end;
|
|
|
|
procedure pbDecodeFieldSFixed64(const Field: TpbProtoBufDecodeField; var Value: Int64);
|
|
begin
|
|
case Field.WireType of
|
|
pwt32Bit : Value := PInt32(Field.WireDataPtr)^;
|
|
pwt64Bit : Value := PInt64(Field.WireDataPtr)^;
|
|
else
|
|
raise EpbDecodeError.Create(SErr_InvalidWireType);
|
|
end;
|
|
end;
|
|
|
|
procedure pbDecodeFieldBool(const Field: TpbProtoBufDecodeField; var Value: Boolean);
|
|
begin
|
|
case Field.WireType of
|
|
pwt32Bit : Value := PInt32(Field.WireDataPtr)^ <> 0;
|
|
pwt64Bit : Value := PInt64(Field.WireDataPtr)^ <> 0;
|
|
pwtVarInt : Value := pbVarIntToUInt32(Field.ValueVarInt) <> 0;
|
|
else
|
|
raise EpbDecodeError.Create(SErr_InvalidWireType);
|
|
end;
|
|
end;
|
|
|
|
function pbDecodeFieldString(const Field: TpbProtoBufDecodeField; var Value: RawByteString): Integer;
|
|
var
|
|
S : RawByteString;
|
|
L : Integer;
|
|
begin
|
|
case Field.WireType of
|
|
pwtVarBytes :
|
|
begin
|
|
L := Field.ValueVarBytesLen;
|
|
SetLength(S, L);
|
|
if L > 0 then
|
|
Move(Field.ValueVarBytesPtr^, Pointer(S)^, L);
|
|
Value := S;
|
|
Result := L;
|
|
end;
|
|
else
|
|
raise EpbDecodeError.Create(SErr_InvalidWireType);
|
|
end;
|
|
end;
|
|
|
|
function pbDecodeFieldBytes(const Field: TpbProtoBufDecodeField; var ValueBuf; const ValueBufSize: Integer): Integer;
|
|
var
|
|
L : Integer;
|
|
begin
|
|
case Field.WireType of
|
|
pwtVarBytes :
|
|
begin
|
|
L := Field.ValueVarBytesLen;
|
|
if ValueBufSize < L then
|
|
raise EpbDecodeError.Create(SErr_BufferTooSmall);
|
|
if L > 0 then
|
|
Move(Field.ValueVarBytesPtr^, ValueBuf, L);
|
|
Result := L;
|
|
end;
|
|
else
|
|
raise EpbDecodeError.Create(SErr_InvalidWireType);
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
{ }
|
|
{ Test cases }
|
|
{ }
|
|
{$IFDEF PROTOBUF_TEST}
|
|
{$ASSERTIONS ON}
|
|
{$IFNDEF SupportsUInt64}{$WARNINGS OFF}{$ENDIF}
|
|
procedure Test_VarInt;
|
|
var I, J : TpbVarInt;
|
|
A : Word32;
|
|
begin
|
|
// InitZero
|
|
pbVarIntInitZero(I);
|
|
Assert(I.EncSize = 1);
|
|
Assert(I.EncData[0] = 0);
|
|
Assert(pbVarIntToUInt32(I) = 0);
|
|
|
|
// pbVarIntEquals
|
|
pbVarIntInitUInt32(I, 0);
|
|
pbVarIntInitZero(J);
|
|
Assert(pbVarIntEquals(I, J));
|
|
|
|
pbVarIntInitUInt32(I, 0);
|
|
pbVarIntInitUInt32(J, 1);
|
|
Assert(not pbVarIntEquals(I, J));
|
|
|
|
// pbVarIntInitWord32
|
|
pbVarIntInitUInt32(I, 0);
|
|
Assert(I.EncSize = 1);
|
|
Assert(I.EncData[0] = 0);
|
|
Assert(pbVarIntToUInt32(I) = 0);
|
|
|
|
pbVarIntInitUInt32(I, 1);
|
|
Assert(I.EncSize = 1);
|
|
Assert(I.EncData[0] = 1);
|
|
Assert(pbVarIntToUInt32(I) = 1);
|
|
|
|
pbVarIntInitUInt32(I, $7F);
|
|
Assert(I.EncSize = 1);
|
|
Assert(I.EncData[0] = $7F);
|
|
Assert(pbVarIntToUInt32(I) = $7F);
|
|
|
|
pbVarIntInitUInt32(I, $80);
|
|
Assert(I.EncSize = 2);
|
|
Assert(I.EncData[0] = $80);
|
|
Assert(I.EncData[1] = $01);
|
|
Assert(pbVarIntToUInt32(I) = $80);
|
|
|
|
pbVarIntInitUInt32(I, $81);
|
|
Assert(I.EncSize = 2);
|
|
Assert(I.EncData[0] = $81);
|
|
Assert(I.EncData[1] = $01);
|
|
Assert(pbVarIntToUInt32(I) = $81);
|
|
|
|
pbVarIntInitUInt32(I, $100);
|
|
Assert(I.EncSize = 2);
|
|
Assert(I.EncData[0] = $80);
|
|
Assert(I.EncData[1] = $02);
|
|
Assert(pbVarIntToUInt32(I) = $100);
|
|
|
|
pbVarIntInitUInt32(I, $3FFF);
|
|
Assert(I.EncSize = 2);
|
|
Assert(I.EncData[0] = $FF);
|
|
Assert(I.EncData[1] = $7F);
|
|
Assert(pbVarIntToUInt32(I) = $3FFF);
|
|
|
|
pbVarIntInitUInt32(I, $4000);
|
|
Assert(I.EncSize = 3);
|
|
Assert(I.EncData[0] = $80);
|
|
Assert(I.EncData[1] = $80);
|
|
Assert(I.EncData[2] = $01);
|
|
Assert(pbVarIntToUInt32(I) = $4000);
|
|
|
|
pbVarIntInitUInt32(I, $4001);
|
|
Assert(I.EncSize = 3);
|
|
Assert(I.EncData[0] = $81);
|
|
Assert(I.EncData[1] = $80);
|
|
Assert(I.EncData[2] = $01);
|
|
Assert(pbVarIntToUInt32(I) = $4001);
|
|
|
|
pbVarIntInitUInt32(I, $1FFFFF);
|
|
Assert(I.EncSize = 3);
|
|
Assert(I.EncData[0] = $FF);
|
|
Assert(I.EncData[1] = $FF);
|
|
Assert(I.EncData[2] = $7F);
|
|
Assert(pbVarIntToUInt32(I) = $1FFFFF);
|
|
|
|
pbVarIntInitUInt32(I, $200000);
|
|
Assert(I.EncSize = 4);
|
|
Assert(I.EncData[0] = $80);
|
|
Assert(I.EncData[1] = $80);
|
|
Assert(I.EncData[2] = $80);
|
|
Assert(I.EncData[3] = $01);
|
|
Assert(pbVarIntToUInt32(I) = $200000);
|
|
|
|
pbVarIntInitUInt32(I, $FFFFFFF);
|
|
Assert(I.EncSize = 4);
|
|
Assert(I.EncData[0] = $FF);
|
|
Assert(I.EncData[1] = $FF);
|
|
Assert(I.EncData[2] = $FF);
|
|
Assert(I.EncData[3] = $7F);
|
|
Assert(pbVarIntToUInt32(I) = $FFFFFFF);
|
|
|
|
pbVarIntInitUInt32(I, $10000000);
|
|
Assert(I.EncSize = 5);
|
|
Assert(I.EncData[0] = $80);
|
|
Assert(I.EncData[1] = $80);
|
|
Assert(I.EncData[2] = $80);
|
|
Assert(I.EncData[3] = $80);
|
|
Assert(I.EncData[4] = $01);
|
|
Assert(pbVarIntToUInt32(I) = $10000000);
|
|
|
|
pbVarIntInitUInt32(I, $12345678);
|
|
Assert(I.EncSize = 5);
|
|
Assert(I.EncData[0] = $F8);
|
|
Assert(I.EncData[1] = $AC);
|
|
Assert(I.EncData[2] = $D1);
|
|
Assert(I.EncData[3] = $91);
|
|
Assert(I.EncData[4] = $01);
|
|
Assert(pbVarIntToUInt32(I) = $12345678);
|
|
|
|
pbVarIntInitUInt32(I, $FFFFFFFF);
|
|
Assert(I.EncSize = 5);
|
|
Assert(I.EncData[0] = $FF);
|
|
Assert(I.EncData[1] = $FF);
|
|
Assert(I.EncData[2] = $FF);
|
|
Assert(I.EncData[3] = $FF);
|
|
Assert(I.EncData[4] = $0F);
|
|
Assert(pbVarIntToUInt32(I) = $FFFFFFFF);
|
|
|
|
// pbVarIntInitBinBuf
|
|
A := 0;
|
|
pbVarIntInitBinBuf(I, A, SizeOf(A));
|
|
Assert(I.EncSize = 1);
|
|
Assert(I.EncData[0] = 0);
|
|
Assert(pbVarIntToUInt32(I) = 0);
|
|
|
|
A := 1;
|
|
pbVarIntInitBinBuf(I, A, SizeOf(A));
|
|
Assert(I.EncSize = 1);
|
|
Assert(I.EncData[0] = 1);
|
|
Assert(pbVarIntToUInt32(I) = 1);
|
|
|
|
A := $7F;
|
|
pbVarIntInitBinBuf(I, A, SizeOf(A));
|
|
Assert(I.EncSize = 1);
|
|
Assert(I.EncData[0] = $7F);
|
|
Assert(pbVarIntToUInt32(I) = $7F);
|
|
|
|
A := $80;
|
|
pbVarIntInitBinBuf(I, A, SizeOf(A));
|
|
Assert(I.EncSize = 2);
|
|
Assert(I.EncData[0] = $80);
|
|
Assert(I.EncData[1] = $01);
|
|
Assert(pbVarIntToUInt32(I) = $80);
|
|
|
|
A := $81;
|
|
pbVarIntInitBinBuf(I, A, SizeOf(A));
|
|
Assert(I.EncSize = 2);
|
|
Assert(I.EncData[0] = $81);
|
|
Assert(I.EncData[1] = $01);
|
|
Assert(pbVarIntToUInt32(I) = $81);
|
|
|
|
A := $100;
|
|
pbVarIntInitBinBuf(I, A, SizeOf(A));
|
|
Assert(I.EncSize = 2);
|
|
Assert(I.EncData[0] = $80);
|
|
Assert(I.EncData[1] = $02);
|
|
Assert(pbVarIntToUInt32(I) = $100);
|
|
|
|
A := $3FFF;
|
|
pbVarIntInitBinBuf(I, A, SizeOf(A));
|
|
Assert(I.EncSize = 2);
|
|
Assert(I.EncData[0] = $FF);
|
|
Assert(I.EncData[1] = $7F);
|
|
Assert(pbVarIntToUInt32(I) = $3FFF);
|
|
|
|
A := $4000;
|
|
pbVarIntInitBinBuf(I, A, SizeOf(A));
|
|
Assert(I.EncSize = 3);
|
|
Assert(I.EncData[0] = $80);
|
|
Assert(I.EncData[1] = $80);
|
|
Assert(I.EncData[2] = $01);
|
|
Assert(pbVarIntToUInt32(I) = $4000);
|
|
|
|
A := $4001;
|
|
pbVarIntInitBinBuf(I, A, SizeOf(A));
|
|
Assert(I.EncSize = 3);
|
|
Assert(I.EncData[0] = $81);
|
|
Assert(I.EncData[1] = $80);
|
|
Assert(I.EncData[2] = $01);
|
|
Assert(pbVarIntToUInt32(I) = $4001);
|
|
|
|
A := $200000;
|
|
pbVarIntInitBinBuf(I, A, SizeOf(A));
|
|
Assert(I.EncSize = 4);
|
|
Assert(I.EncData[0] = $80);
|
|
Assert(I.EncData[1] = $80);
|
|
Assert(I.EncData[2] = $80);
|
|
Assert(I.EncData[3] = $01);
|
|
Assert(pbVarIntToUInt32(I) = $200000);
|
|
|
|
A := $10000000;
|
|
pbVarIntInitBinBuf(I, A, SizeOf(A));
|
|
Assert(I.EncSize = 5);
|
|
Assert(I.EncData[0] = $80);
|
|
Assert(I.EncData[1] = $80);
|
|
Assert(I.EncData[2] = $80);
|
|
Assert(I.EncData[3] = $80);
|
|
Assert(I.EncData[4] = $01);
|
|
Assert(pbVarIntToUInt32(I) = $10000000);
|
|
|
|
A := $12345678;
|
|
pbVarIntInitBinBuf(I, A, SizeOf(A));
|
|
Assert(I.EncSize = 5);
|
|
Assert(I.EncData[0] = $F8);
|
|
Assert(I.EncData[1] = $AC);
|
|
Assert(I.EncData[2] = $D1);
|
|
Assert(I.EncData[3] = $91);
|
|
Assert(I.EncData[4] = $01);
|
|
Assert(pbVarIntToUInt32(I) = $12345678);
|
|
|
|
A := $FFFFFFFF;
|
|
pbVarIntInitBinBuf(I, A, SizeOf(A));
|
|
Assert(I.EncSize = 5);
|
|
Assert(I.EncData[0] = $FF);
|
|
Assert(I.EncData[1] = $FF);
|
|
Assert(I.EncData[2] = $FF);
|
|
Assert(I.EncData[3] = $FF);
|
|
Assert(I.EncData[4] = $0F);
|
|
Assert(pbVarIntToUInt32(I) = $FFFFFFFF);
|
|
|
|
// pbVarIntInitEncBuf
|
|
pbVarIntInitUInt32(I, 0);
|
|
Assert(pbVarIntInitEncBuf(J, I.EncData[0], SizeOf(I.EncData)) = I.EncSize);
|
|
Assert(pbVarIntToUInt32(J) = 0);
|
|
|
|
pbVarIntInitUInt32(I, 1);
|
|
Assert(pbVarIntInitEncBuf(J, I.EncData[0], SizeOf(I.EncData)) = I.EncSize);
|
|
Assert(pbVarIntToUInt32(J) = 1);
|
|
|
|
pbVarIntInitUInt32(I, $80);
|
|
Assert(pbVarIntInitEncBuf(J, I.EncData[0], SizeOf(I.EncData)) = I.EncSize);
|
|
Assert(pbVarIntToUInt32(J) = $80);
|
|
|
|
pbVarIntInitUInt32(I, $3FFF);
|
|
Assert(pbVarIntInitEncBuf(J, I.EncData[0], SizeOf(I.EncData)) = I.EncSize);
|
|
Assert(pbVarIntToUInt32(J) = $3FFF);
|
|
|
|
pbVarIntInitUInt32(I, $4000);
|
|
Assert(pbVarIntInitEncBuf(J, I.EncData[0], SizeOf(I.EncData)) = I.EncSize);
|
|
Assert(pbVarIntToUInt32(J) = $4000);
|
|
|
|
pbVarIntInitUInt32(I, $4001);
|
|
Assert(pbVarIntInitEncBuf(J, I.EncData[0], SizeOf(I.EncData)) = I.EncSize);
|
|
Assert(pbVarIntToUInt32(J) = $4001);
|
|
|
|
pbVarIntInitUInt32(I, $12345678);
|
|
Assert(pbVarIntInitEncBuf(J, I.EncData[0], SizeOf(I.EncData)) = I.EncSize);
|
|
Assert(pbVarIntToUInt32(J) = $12345678);
|
|
|
|
pbVarIntInitUInt32(I, $FFFFFFFF);
|
|
Assert(pbVarIntInitEncBuf(J, I.EncData[0], SizeOf(I.EncData)) = I.EncSize);
|
|
Assert(pbVarIntToUInt32(J) = $FFFFFFFF);
|
|
|
|
// pbVarIntToBinBuf
|
|
pbVarIntInitUInt32(I, 0);
|
|
pbVarIntToBinBuf(I, A, SizeOf(A));
|
|
Assert(A = 0);
|
|
|
|
pbVarIntInitUInt32(I, 1);
|
|
pbVarIntToBinBuf(I, A, SizeOf(A));
|
|
Assert(A = 1);
|
|
|
|
pbVarIntInitUInt32(I, $7F);
|
|
pbVarIntToBinBuf(I, A, SizeOf(A));
|
|
Assert(A = $7F);
|
|
|
|
pbVarIntInitUInt32(I, $80);
|
|
pbVarIntToBinBuf(I, A, SizeOf(A));
|
|
Assert(A = $80);
|
|
|
|
pbVarIntInitUInt32(I, $81);
|
|
pbVarIntToBinBuf(I, A, SizeOf(A));
|
|
Assert(A = $81);
|
|
|
|
pbVarIntInitUInt32(I, $3FFF);
|
|
pbVarIntToBinBuf(I, A, SizeOf(A));
|
|
Assert(A = $3FFF);
|
|
|
|
pbVarIntInitUInt32(I, $4000);
|
|
pbVarIntToBinBuf(I, A, SizeOf(A));
|
|
Assert(A = $4000);
|
|
|
|
pbVarIntInitUInt32(I, $4001);
|
|
pbVarIntToBinBuf(I, A, SizeOf(A));
|
|
Assert(A = $4001);
|
|
|
|
pbVarIntInitUInt32(I, $200000);
|
|
pbVarIntToBinBuf(I, A, SizeOf(A));
|
|
Assert(A = $200000);
|
|
|
|
pbVarIntInitUInt32(I, $10000000);
|
|
pbVarIntToBinBuf(I, A, SizeOf(A));
|
|
Assert(A = $10000000);
|
|
|
|
pbVarIntInitUInt32(I, $12345678);
|
|
pbVarIntToBinBuf(I, A, SizeOf(A));
|
|
Assert(A = $12345678);
|
|
|
|
pbVarIntInitUInt32(I, $FFFFFFFF);
|
|
pbVarIntToBinBuf(I, A, SizeOf(A));
|
|
Assert(A = $FFFFFFFF);
|
|
|
|
// pbSInt32ToUInt32
|
|
Assert(pbSInt32ToUInt32(0) = 0);
|
|
Assert(pbSInt32ToUInt32(-1) = 1);
|
|
Assert(pbSInt32ToUInt32(1) = 2);
|
|
Assert(pbSInt32ToUInt32(-2) = 3);
|
|
Assert(pbSInt32ToUInt32(2) = 4);
|
|
Assert(pbSInt32ToUInt32(-3) = 5);
|
|
Assert(pbSInt32ToUInt32(2147483647) = $FFFFFFFE);
|
|
Assert(pbSInt32ToUInt32(-2147483648) = $FFFFFFFF);
|
|
|
|
// pbUInt32ToSInt32
|
|
Assert(pbUInt32ToSInt32(0) = 0);
|
|
Assert(pbUInt32ToSInt32(1) = -1);
|
|
Assert(pbUInt32ToSInt32(2) = 1);
|
|
Assert(pbUInt32ToSInt32(3) = -2);
|
|
Assert(pbUInt32ToSInt32(4) = 2);
|
|
Assert(pbUInt32ToSInt32(5) = -3);
|
|
Assert(pbUInt32ToSInt32($FFFFFFFE) = 2147483647);
|
|
Assert(pbUInt32ToSInt32($FFFFFFFF) = -2147483648);
|
|
|
|
// pbVarIntInitSInt32
|
|
pbVarIntInitSInt32(I, 0);
|
|
Assert(pbVarIntToSInt32(I) = 0);
|
|
|
|
pbVarIntInitSInt32(I, -1);
|
|
Assert(pbVarIntToSInt32(I) = -1);
|
|
|
|
pbVarIntInitSInt32(I, 1);
|
|
Assert(pbVarIntToSInt32(I) = 1);
|
|
|
|
pbVarIntInitSInt32(I, 2147483647);
|
|
Assert(pbVarIntToSInt32(I) = 2147483647);
|
|
|
|
pbVarIntInitSInt32(I, -2147483648);
|
|
Assert(pbVarIntToSInt32(I) = -2147483648);
|
|
|
|
// pbSInt64ToUInt64
|
|
Assert(pbSInt64ToUInt64(0) = 0);
|
|
Assert(pbSInt64ToUInt64(-1) = 1);
|
|
Assert(pbSInt64ToUInt64(1) = 2);
|
|
Assert(pbSInt64ToUInt64(-2) = 3);
|
|
Assert(pbSInt64ToUInt64(2) = 4);
|
|
Assert(pbSInt64ToUInt64(-3) = 5);
|
|
Assert(pbSInt64ToUInt64(2147483647) = $FFFFFFFE);
|
|
Assert(pbSInt64ToUInt64(-2147483648) = $FFFFFFFF);
|
|
Assert(pbSInt64ToUInt64(2147483648) = $100000000);
|
|
Assert(pbSInt64ToUInt64(-2147483649) = $100000001);
|
|
Assert(pbSInt64ToUInt64(4611686018427387903) = $7FFFFFFFFFFFFFFE);
|
|
Assert(pbSInt64ToUInt64(-4611686018427387904) = $7FFFFFFFFFFFFFFF);
|
|
Assert(pbSInt64ToUInt64(4611686018427387904) = $8000000000000000);
|
|
Assert(pbSInt64ToUInt64(-4611686018427387905) = $8000000000000001);
|
|
Assert(pbSInt64ToUInt64(9223372036854775807) = $FFFFFFFFFFFFFFFE);
|
|
Assert(pbSInt64ToUInt64(-9223372036854775808) = $FFFFFFFFFFFFFFFF);
|
|
|
|
// pbUInt64ToSInt64
|
|
Assert(pbUInt64ToSInt64(0) = 0);
|
|
Assert(pbUInt64ToSInt64(1) = -1);
|
|
Assert(pbUInt64ToSInt64(2) = 1);
|
|
Assert(pbUInt64ToSInt64(3) = -2);
|
|
Assert(pbUInt64ToSInt64(4) = 2);
|
|
Assert(pbUInt64ToSInt64(5) = -3);
|
|
Assert(pbUInt64ToSInt64($FFFFFFFE) = 2147483647);
|
|
Assert(pbUInt64ToSInt64($FFFFFFFF) = -2147483648);
|
|
Assert(pbUInt64ToSInt64($100000000) = 2147483648);
|
|
Assert(pbUInt64ToSInt64($100000001) = -2147483649);
|
|
Assert(pbUInt64ToSInt64($7FFFFFFFFFFFFFFE) = 4611686018427387903);
|
|
Assert(pbUInt64ToSInt64($7FFFFFFFFFFFFFFF) = -4611686018427387904);
|
|
Assert(pbUInt64ToSInt64($8000000000000000) = 4611686018427387904);
|
|
Assert(pbUInt64ToSInt64($8000000000000001) = -4611686018427387905);
|
|
Assert(pbUInt64ToSInt64($FFFFFFFFFFFFFFFE) = 9223372036854775807);
|
|
Assert(pbUInt64ToSInt64($FFFFFFFFFFFFFFFF) = -9223372036854775808);
|
|
|
|
// pbVarIntInitSInt64
|
|
pbVarIntInitSInt64(I, 0);
|
|
Assert(pbVarIntToSInt64(I) = 0);
|
|
|
|
pbVarIntInitSInt64(I, -1);
|
|
Assert(pbVarIntToSInt64(I) = -1);
|
|
|
|
pbVarIntInitSInt64(I, 1);
|
|
Assert(pbVarIntToSInt64(I) = 1);
|
|
|
|
pbVarIntInitSInt64(I, 2147483647);
|
|
Assert(pbVarIntToSInt64(I) = 2147483647);
|
|
|
|
pbVarIntInitSInt64(I, -2147483648);
|
|
Assert(pbVarIntToSInt64(I) = -2147483648);
|
|
|
|
pbVarIntInitSInt64(I, 2147483648);
|
|
Assert(pbVarIntToSInt64(I) = 2147483648);
|
|
|
|
pbVarIntInitSInt64(I, -2147483649);
|
|
Assert(pbVarIntToSInt64(I) = -2147483649);
|
|
|
|
pbVarIntInitSInt64(I, 9223372036854775807);
|
|
Assert(pbVarIntToSInt64(I) = 9223372036854775807);
|
|
|
|
pbVarIntInitSInt64(I, -9223372036854775808);
|
|
Assert(pbVarIntToSInt64(I) = -9223372036854775808);
|
|
end;
|
|
|
|
procedure Test_Encode;
|
|
var
|
|
B : array[0..1023] of Byte;
|
|
begin
|
|
FillChar(B, SizeOf(B), 0);
|
|
|
|
Assert(pbEncodeFieldKey(B[0], SizeOf(B), 3, pwtVarBytes) = 1);
|
|
Assert(B[0] = $1A);
|
|
|
|
Assert(pbEncodeFieldString(B[0], SizeOf(B), 2, 'testing') = 9);
|
|
Assert(B[0] = $12);
|
|
Assert(B[1] = $07);
|
|
Assert(B[2] = $74);
|
|
Assert(B[8] = $67);
|
|
|
|
Assert(pbEncodeFieldUInt32(B[0], SizeOf(B), 2, 12) = 2);
|
|
Assert(B[0] = $10);
|
|
Assert(B[1] = $0C);
|
|
|
|
FillChar(B, SizeOf(B), 0);
|
|
|
|
Assert(pbEncodeFieldString(B[0], 0, 2, 'testing') = 9);
|
|
Assert(B[0] = 0);
|
|
Assert(B[1] = 0);
|
|
Assert(B[2] = 0);
|
|
Assert(B[8] = 0);
|
|
|
|
Assert(pbEncodeFieldUInt32(B[0], 0, 2, 12) = 2);
|
|
Assert(B[0] = 0);
|
|
Assert(B[1] = 0);
|
|
end;
|
|
|
|
procedure Test_Decode_CallbackProc(const Field: TpbProtoBufDecodeField; const Data: Pointer);
|
|
var
|
|
A : Word32;
|
|
B : Int64;
|
|
C : RawByteString;
|
|
begin
|
|
case Integer(Data) of
|
|
1 : case Field.FieldNum of
|
|
4 : begin
|
|
Assert(Field.WireType = pwtVarInt);
|
|
Assert(pbVarIntToUInt32(Field.ValueVarInt) = 13);
|
|
A := 0;
|
|
pbDecodeFieldUInt32(Field, A);
|
|
Assert(A = 13);
|
|
end;
|
|
5 : begin
|
|
Assert(Field.WireType = pwtVarInt);
|
|
Assert(pbVarIntToSInt64(Field.ValueVarInt) = -1);
|
|
B := 0;
|
|
pbDecodeFieldSInt64(Field, B);
|
|
Assert(B = -1);
|
|
end;
|
|
6 : begin
|
|
Assert(Field.WireType = pwtVarBytes);
|
|
pbDecodeFieldString(Field, C);
|
|
Assert(C = 'ABC');
|
|
end;
|
|
else
|
|
Assert(False);
|
|
end;
|
|
else
|
|
Assert(False);
|
|
end;
|
|
end;
|
|
|
|
procedure Test_Decode;
|
|
var
|
|
B : array[0..1023] of Byte;
|
|
P : PByte;
|
|
L, N : Integer;
|
|
begin
|
|
P := @B[0];
|
|
L := SizeOf(B);
|
|
N := pbEncodeFieldInt32(P^, L, 4, 13);
|
|
Dec(L, N);
|
|
Inc(P, N);
|
|
N := pbEncodeFieldSInt64(P^, L, 5, -1);
|
|
Dec(L, N);
|
|
Inc(P, N);
|
|
N := pbEncodeFieldString(P^, L, 6, 'ABC');
|
|
Dec(L, N);
|
|
|
|
pbDecodeProtoBuf(B[0], SizeOf(B) - L, Test_Decode_CallbackProc, Ptr(1));
|
|
end;
|
|
|
|
procedure Test;
|
|
begin
|
|
Test_VarInt;
|
|
Test_Encode;
|
|
Test_Decode;
|
|
end;
|
|
{$ENDIF}
|
|
|
|
|
|
|
|
end.
|
|
|