# AnsweredVariable length encoding - 'C' code converted into ABL

#### Cecil

##### 19+ years progress programming and still learning.
I need to be able to convert some C code into ABL details below.

The Remaining Length is the number of bytes remaining within the current packet, including data in the variable header and the payload. The Remaining Length does not include the bytes used to encode the Remaining Length.

The Remaining Length is encoded using a variable length encoding scheme which uses a single byte for values up to 127. Larger values are handled as follows. The least significant seven bits of each byte encode the data, and the most significant bit is used to indicate that there are following bytes in the representation. Thus each byte encodes 128 values and a "continuation bit". The maximum number of bytes in the Remaining Length field is four.

Non normative comment

For example, the number 64 decimal is encoded as a single byte, decimal value 64, hexadecimal 0x40. The number 321 decimal (= 65 + 2*128) is encoded as two bytes, least significant first. The first byte is 65+128 = 193. Note that the top bit is set to indicate at least one following byte. The second byte is 2.

Non normative comment

This allows applications to send Control Packets of size up to 268,435,455 (256 MB). The representation of this number on the wire is: 0xFF, 0xFF, 0xFF, 0x7F.

Table 2.4 shows the Remaining Length values represented by increasing numbers of bytes.

#### Table 2.4 Size of Remaining Length field​

 Digits​ From​ To​ 1​ 0 (0x00) 127 (0x7F) 2​ 128 (0x80, 0x01) 16 383 (0xFF, 0x7F) 3​ 16 384 (0x80, 0x80, 0x01) 2 097 151 (0xFF, 0xFF, 0x7F) 4​ 2 097 152 (0x80, 0x80, 0x80, 0x01) 268 435 455 (0xFF, 0xFF, 0xFF, 0x7F)

Non normative comment

The algorithm for encoding a non negative integer (X) into the variable length encoding scheme is as follows:

do

encodedByte = X MOD 128

X = X DIV 128

// if there are more data to encode, set the top bit of this byte

if ( X > 0 )

encodedByte = encodedByte OR 128

endif

'output' encodedByte

while ( X > 0 )

Where MOD is the modulo operator (% in C), DIV is integer division (/ in C), and OR is bit-wise or (| in C).

Non normative comment

The algorithm for decoding the Remaining Length field is as follows:

multiplier = 1

value = 0

do

encodedByte = 'next byte from stream'

value += (encodedByte AND 127) * multiplier

multiplier *= 128

if (multiplier > 128*128*128)

throw Error(Malformed Remaining Length)

while ((encodedByte AND 128) != 0)

where AND is the bit-wise and operator (& in C).

When this algorithm terminates, value contains the Remaining Length value.

#### Jean-Christophe Cardot

##### Member
Something like that?

Code:
``````DEFINE VARIABLE i            AS INTEGER   NO-UNDO.
DEFINE VARIABLE iByte        AS INTEGER   NO-UNDO.
DEFINE VARIABLE iEncodedByte AS INTEGER   EXTENT 4 INITIAL -1 NO-UNDO.
DEFINE VARIABLE iMultiplier  AS INTEGER   NO-UNDO.
DEFINE VARIABLE iValue       AS INTEGER   INITIAL 1728 NO-UNDO. /* value to encode */.

/* encode */

i = 1.

DO WHILE iValue > 0:
iEncodedByte[i] = iValue MODULO 128.
iValue = TRUNCATE(iValue / 128, 0).
IF iValue > 0 THEN DO:
PUT-BITS( iEncodedByte[i], 8, 1) = 1.
i = i + 1.
END.
END.

MESSAGE i "bytes" SKIP
iEncodedByte iEncodedByte iEncodedByte iEncodedByte

/* decode */

i           = 0.
iValue      = 0.
iMultiplier = 1.

DO WHILE TRUE:
i = i + 1.
iByte = iEncodedByte[i].
IF iByte < 0 THEN LEAVE.
PUT-BITS(iByte, 8, 1) = 0.
iValue = iValue + iByte * iMultiplier.
iMultiplier = iMultiplier * 128.
IF iMultiplier > 128 * 128 * 128 THEN DO:
MESSAGE "Malformed Remaining Length"
LEAVE.
END.
IF GET-BITS(iEncodedByte[i],8,1) = 0 THEN
LEAVE.
END.

MESSAGE iValue

Last edited:
• Cecil

#### Cecil

##### 19+ years progress programming and still learning.
Big thank you

I was just struggling and I was overthinking the issue.

I have refactored your code into functions and made some minor tweeks.

Code:
``````// encode
Function variableLengthEncoding returns integer extent 4 (input iValue as integer,
output numBytesUsed as integer):

define variable iByte        as integer   no-undo.
define variable iEncodedByte as integer   extent 4 INITIAL -1 NO-UNDO.
define variable iMultiplier  as integer   no-undo.

// input value range check
if iValue lt 0x00 or iValue gt 0xfffffff Then
do:
numBytesUsed = ?.
return iEncodedByte.
end.

numBytesUsed = 1.

do while iValue gt 0:
iEncodedByte[numBytesUsed] = iValue modulo 128.

iValue = truncate(iValue / 128, 0).

if iValue gt 0 then
do:
put-bits( iEncodedByte[numBytesUsed], 8, 1) = 1.
numBytesUsed = numBytesUsed + 1.
end.
end.

return iEncodedByte.

end function.

//decode
function variableLengthDecoding returns integer (input iEncodedByte as integer extent):

define variable iBytePosition as integer no-undo.
define variable iByte         as integer no-undo.
define variable iValue        as integer no-undo.
define variable iMultiplier   as integer no-undo.

assign
iBytePosition = 0
iValue        = 0
iMultiplier   = 1.

DECODING-LOOP:
do while true:
iBytePosition = iBytePosition + 1.
iByte = iEncodedByte[iBytePosition].

if iByte lt 0 then
leave.

put-bits(iByte, 8, 1) = 0.

iValue = iValue + iByte * iMultiplier.

iMultiplier = iMultiplier * 128.

if iMultiplier gt 0x200000 THEN       // dec 128 * 128 * 128 = hex 0x200000
do:
//MESSAGE "Malformed Remaining Length"  VIEW-AS ALERT-BOX ERROR BUTTONS OK.
leave DECODING-LOOP.
end.

if get-bits(iEncodedByte[iBytePosition],8,1) eq 0 then
leave DECODING-LOOP.
END.

return iValue.

end function .

define variable numBytesUsed    as integer  no-undo.
define variable iValue          as integer  no-undo.
define variable iEncodedByte    as integer  extent 4 no-undo.
define variable iCompareCheck   as integer  no-undo.
define variable dataStream      as memptr   no-undo.

iValue = random(1, 268435455).

iCompareCheck = iValue.
//iValue = -1000.

iEncodedByte = variableLengthEncoding(input  iValue,
output numBytesUsed).

If numBytesUsed eq ? Then
Do:
message substitute("Invalid value provided &1", quoter(iValue))
view-as alert-box error title "Variable Length Encoding".
return.
End.

message "Encode Value: " iValue skip
"Bytes Used:" numBytesUsed  skip
"Encoded Bytes: " iEncodedByte iEncodedByte iEncodedByte iEncodedByte
view-as alert-box info buttons ok title "Variable Length Encoding".

set-size(dataStream) = 0.
set-size(dataStream) = 2 + numBytesUsed.  // first two btyes are reserved

assign
put-byte(dataStream, 3) = iEncodedByte when iEncodedByte ne -1
put-byte(dataStream, 4) = iEncodedByte when iEncodedByte ne -1
put-byte(dataStream, 5) = iEncodedByte when iEncodedByte ne -1
put-byte(dataStream, 6) = iEncodedByte when iEncodedByte ne -1
.

iEncodedByte = -1.

assign
iEncodedByte = get-byte(dataStream, 3) when get-size(dataStream) ge 3
iEncodedByte = get-byte(dataStream, 4) when get-size(dataStream) ge 4
iEncodedByte = get-byte(dataStream, 5) when get-size(dataStream) ge 5
iEncodedByte = get-byte(dataStream, 6) when get-size(dataStream) ge 6
.

// decode the encoded btyes.
iValue = variableLengthDecoding(input iEncodedByte).

message "Encoded Bytes: " iEncodedByte iEncodedByte iEncodedByte iEncodedByte skip
"Decoded Value: " iValue skip
"Successful:" logical(iCompareCheck eq iValue)
view-as alert-box info buttons ok title "Variable Length Decoding".

finally:
set-size(dataStream) = 0.
end.``````

#### Jean-Christophe Cardot

##### Member
Glad it helped It was a nice little exercise to end the day A
Replies
0
Views
517
AXMIM
A
T
Replies
0
Views
492
Thierry Ciot
T
Replies
6
Views
1K
G
Replies
0
Views
593
George Potemkin
G
G
Replies
0
Views
761
George Potemkin
G