You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by cd...@apache.org on 2025/03/18 16:48:14 UTC

(plc4x) branch develop updated: feat: Add support for variable length unsigned integers in mspec.

This is an automated email from the ASF dual-hosted git repository.

cdutz pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/plc4x.git


The following commit(s) were added to refs/heads/develop by this push:
     new b3922460c1 feat: Add support for variable length unsigned integers in mspec.
b3922460c1 is described below

commit b3922460c194775501b004c65a78c799eef61f21
Author: Christofer Dutz <ch...@c-ware.de>
AuthorDate: Tue Mar 18 17:47:58 2025 +0100

    feat: Add support for variable length unsigned integers in mspec.
---
 .../language/java/JavaLanguageTemplateHelper.java  |  9 ++++++++
 .../templates/java/complex-type-template.java.ftlh |  4 ++++
 .../java/spi/generation/ReadBufferByteBased.java   | 19 ++++++++++++++++
 .../plc4x/java/spi/generation/StaticHelper.java    | 10 +++++++++
 .../java/spi/generation/WriteBufferByteBased.java  | 25 ++++++++++++++++++++++
 5 files changed, 67 insertions(+)

diff --git a/code-generation/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java b/code-generation/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java
index 5e7fb08763..1168219fe2 100644
--- a/code-generation/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java
+++ b/code-generation/language-java/src/main/java/org/apache/plc4x/language/java/JavaLanguageTemplateHelper.java
@@ -1411,4 +1411,13 @@ public class JavaLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHe
         return imports.toString();
     }
 
+    public boolean isVarduintField(Field field) {
+        Optional<Term> encoding = field.getEncoding();
+        if (encoding.isPresent()) {
+            String encodingName = encoding.get().asLiteral().orElseThrow().asStringLiteral().orElseThrow().getValue();
+            return encodingName.equalsIgnoreCase("VARUDINT");
+        }
+        return false;
+    }
+
 }
diff --git a/code-generation/language-java/src/main/resources/templates/java/complex-type-template.java.ftlh b/code-generation/language-java/src/main/resources/templates/java/complex-type-template.java.ftlh
index f242793551..b9a019cb50 100644
--- a/code-generation/language-java/src/main/resources/templates/java/complex-type-template.java.ftlh
+++ b/code-generation/language-java/src/main/resources/templates/java/complex-type-template.java.ftlh
@@ -548,7 +548,11 @@ public<#if type.isDiscriminatedParentTypeDefinition()> abstract</#if> class ${ty
                 <#assign vstringTypeReference = simpleTypeReference.asVstringTypeReference().orElseThrow()>
         lengthInBits += ${helper.toSerializationExpression(simpleField, helper.intTypeReference, vstringTypeReference.getLengthExpression(), parserArguments)};
             <#else>
+                <#if helper.isVarduintField(simpleField)>
+        lengthInBits += GET_VARUDINT_LENGTH_IN_BITS(get${simpleField.getName()?cap_first}());
+                <#else>
         lengthInBits += ${simpleTypeReference.sizeInBits};
+                </#if>
             </#if>
         <#elseif helper.isEnumField(field)>
         lengthInBits += ${helper.getEnumBaseTypeReference(simpleField.type).sizeInBits};
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBufferByteBased.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBufferByteBased.java
index bafc651f65..0d498a955f 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBufferByteBased.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBufferByteBased.java
@@ -311,6 +311,25 @@ public class ReadBufferByteBased implements ReadBuffer, BufferCommons {
                         value += (long) (digit * Math.pow(10, i));
                     }
                     return value;
+                case "VARUDINT":
+                    long result = 0;
+                    int shift = 0;
+                    for (int i = 0; i < 4; i++) {
+                        short b = bi.readShort(true, 8);
+                        // Add the lower 7 bits of b, shifted appropriately.
+                        result = result << shift;
+                        result |= ((long) b & 0x0000007F);
+                        // If the most significant bit is 0, this is the last byte.
+                        if ((b & 0x80) == 0) {
+                            break;
+                        }
+                        shift = 7;
+                        // Ensure we do not exceed the maximum allowed bit length.
+                        if (shift >= bitLength) {
+                            throw new ParseException("var-length-uint exceeds allowed bit length " + bitLength);
+                        }
+                    }
+                    return result;
                 case "default":
                     if (byteOrder == ByteOrder.LITTLE_ENDIAN) {
                         final long longValue = bi.readLong(true, bitLength);
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/StaticHelper.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/StaticHelper.java
index 93883498a9..643f165a2c 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/StaticHelper.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/StaticHelper.java
@@ -126,4 +126,14 @@ public class StaticHelper {
         return hasNext ? COUNT(obj) : 0;
     }    
 
+    public static int GET_VARUDINT_LENGTH_IN_BITS(long value) {
+        int curFieldLengthInBits = 0;
+        long temp = value;
+        do {
+            curFieldLengthInBits += 8;
+            temp >>>= 7;
+        } while (temp != 0);
+        return curFieldLengthInBits;
+    }
+
 }
diff --git a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBufferByteBased.java b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBufferByteBased.java
index 7b0bd65e2f..b0ce1dad87 100644
--- a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBufferByteBased.java
+++ b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBufferByteBased.java
@@ -284,6 +284,31 @@ public class WriteBufferByteBased implements WriteBuffer, BufferCommons {
                     }
                     break;
                 }
+                case "VARUDINT":
+                    // Check that the provided value fits in the allowed bit length.
+                    long maxValue = (1L << bitLength) - 1;
+                    if (value > maxValue) {
+                        throw new SerializationException("Provided value of " + value + " exceeds the max value of " + maxValue);
+                    }
+                    // Determine the number of 7-bit groups (bytes) required.
+                    int numBytes = 0;
+                    long temp = value;
+                    do {
+                        numBytes++;
+                        temp >>>= 7;
+                    } while (temp != 0);
+
+                    // Write each 7-bit group starting from the most significant.
+                    for (int i = numBytes - 1; i >= 0; i--) {
+                        int shift = i * 7;
+                        int b = (int) ((value >> shift) & 0x7F);
+                        // Set the continuation bit for all but the last (least significant) group.
+                        if (i > 0) {
+                            b |= 0x80;
+                        }
+                        bo.writeByte(false, 8, (byte) b);
+                    }
+                    break;
                 case "default":
                     if (byteOrder == ByteOrder.LITTLE_ENDIAN) {
                         value = Long.reverseBytes(value) >> 32;