{******************************************************************************} { } { 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.