Skip to content

Commit b392246

Browse files
committed
feat: Add support for variable length unsigned integers in mspec.
1 parent 72d7a92 commit b392246

File tree

5 files changed

+67
-0
lines changed

5 files changed

+67
-0
lines changed

code-generation/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1411,4 +1411,13 @@ public String getExternalTypeImports() {
14111411
return imports.toString();
14121412
}
14131413

1414+
public boolean isVarduintField(Field field) {
1415+
Optional<Term> encoding = field.getEncoding();
1416+
if (encoding.isPresent()) {
1417+
String encodingName = encoding.get().asLiteral().orElseThrow().asStringLiteral().orElseThrow().getValue();
1418+
return encodingName.equalsIgnoreCase("VARUDINT");
1419+
}
1420+
return false;
1421+
}
1422+
14141423
}

code-generation/language-java/src/main/resources/templates/java/complex-type-template.java.ftlh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -548,7 +548,11 @@ public<#if type.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${ty
548548
<#assign vstringTypeReference = simpleTypeReference.asVstringTypeReference().orElseThrow()>
549549
lengthInBits += ${helper.toSerializationExpression(simpleField, helper.intTypeReference, vstringTypeReference.getLengthExpression(), parserArguments)};
550550
<#else>
551+
<#if helper.isVarduintField(simpleField)>
552+
lengthInBits += GET_VARUDINT_LENGTH_IN_BITS(get${simpleField.getName()?cap_first}());
553+
<#else>
551554
lengthInBits += ${simpleTypeReference.sizeInBits};
555+
</#if>
552556
</#if>
553557
<#elseif helper.isEnumField(field)>
554558
lengthInBits += ${helper.getEnumBaseTypeReference(simpleField.type).sizeInBits};

plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBufferByteBased.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,25 @@ public long readUnsignedLong(String logicalName, int bitLength, WithReaderArgs..
311311
value += (long) (digit * Math.pow(10, i));
312312
}
313313
return value;
314+
case "VARUDINT":
315+
long result = 0;
316+
int shift = 0;
317+
for (int i = 0; i < 4; i++) {
318+
short b = bi.readShort(true, 8);
319+
// Add the lower 7 bits of b, shifted appropriately.
320+
result = result << shift;
321+
result |= ((long) b & 0x0000007F);
322+
// If the most significant bit is 0, this is the last byte.
323+
if ((b & 0x80) == 0) {
324+
break;
325+
}
326+
shift = 7;
327+
// Ensure we do not exceed the maximum allowed bit length.
328+
if (shift >= bitLength) {
329+
throw new ParseException("var-length-uint exceeds allowed bit length " + bitLength);
330+
}
331+
}
332+
return result;
314333
case "default":
315334
if (byteOrder == ByteOrder.LITTLE_ENDIAN) {
316335
final long longValue = bi.readLong(true, bitLength);

plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/StaticHelper.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,4 +126,14 @@ public static int PADCOUNT(Object obj, boolean hasNext) {
126126
return hasNext ? COUNT(obj) : 0;
127127
}
128128

129+
public static int GET_VARUDINT_LENGTH_IN_BITS(long value) {
130+
int curFieldLengthInBits = 0;
131+
long temp = value;
132+
do {
133+
curFieldLengthInBits += 8;
134+
temp >>>= 7;
135+
} while (temp != 0);
136+
return curFieldLengthInBits;
137+
}
138+
129139
}

plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBufferByteBased.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,31 @@ public void writeUnsignedLong(String logicalName, int bitLength, long value, Wit
284284
}
285285
break;
286286
}
287+
case "VARUDINT":
288+
// Check that the provided value fits in the allowed bit length.
289+
long maxValue = (1L << bitLength) - 1;
290+
if (value > maxValue) {
291+
throw new SerializationException("Provided value of " + value + " exceeds the max value of " + maxValue);
292+
}
293+
// Determine the number of 7-bit groups (bytes) required.
294+
int numBytes = 0;
295+
long temp = value;
296+
do {
297+
numBytes++;
298+
temp >>>= 7;
299+
} while (temp != 0);
300+
301+
// Write each 7-bit group starting from the most significant.
302+
for (int i = numBytes - 1; i >= 0; i--) {
303+
int shift = i * 7;
304+
int b = (int) ((value >> shift) & 0x7F);
305+
// Set the continuation bit for all but the last (least significant) group.
306+
if (i > 0) {
307+
b |= 0x80;
308+
}
309+
bo.writeByte(false, 8, (byte) b);
310+
}
311+
break;
287312
case "default":
288313
if (byteOrder == ByteOrder.LITTLE_ENDIAN) {
289314
value = Long.reverseBytes(value) >> 32;

0 commit comments

Comments
 (0)