diff options
| author | Matthias Andreas Benkard <code@mail.matthias.benkard.de> | 2023-12-10 15:28:16 +0100 | 
|---|---|---|
| committer | Matthias Andreas Benkard <code@mail.matthias.benkard.de> | 2023-12-10 15:28:16 +0100 | 
| commit | e9440b54b5442c3b5ef7bffa936152ebbc7b7173 (patch) | |
| tree | fea96cae694e162d1289ae7c5b76ff63d5df8d70 /jgvariant-core/src/main/java | |
| parent | f66fc18b78e78370d288455291d443e1ac173921 (diff) | |
Add Decoder#encode roundtrip tests and fix the bugs discovered.
Change-Id: I21447306d9fc7768e07fafe5bed1d92a3eb42e53
Diffstat (limited to 'jgvariant-core/src/main/java')
| -rw-r--r-- | jgvariant-core/src/main/java/eu/mulk/jgvariant/core/Decoder.java | 52 | 
1 files changed, 36 insertions, 16 deletions
| diff --git a/jgvariant-core/src/main/java/eu/mulk/jgvariant/core/Decoder.java b/jgvariant-core/src/main/java/eu/mulk/jgvariant/core/Decoder.java index a28d792..f605b09 100644 --- a/jgvariant-core/src/main/java/eu/mulk/jgvariant/core/Decoder.java +++ b/jgvariant-core/src/main/java/eu/mulk/jgvariant/core/Decoder.java @@ -5,6 +5,7 @@  package eu.mulk.jgvariant.core;  import static java.lang.Math.max; +import static java.nio.ByteOrder.BIG_ENDIAN;  import static java.nio.ByteOrder.LITTLE_ENDIAN;  import static java.nio.charset.StandardCharsets.UTF_8;  import static java.util.Objects.requireNonNullElse; @@ -440,12 +441,16 @@ public abstract class Decoder<T> {          ArrayList<Integer> framingOffsets = new ArrayList<>(value.size());          int startOffset = byteWriter.position();          for (var element : value) { +          // Align the element. +          var lastRelativeEnd = byteWriter.position() - startOffset; +          byteWriter.write(new byte[align(lastRelativeEnd, alignment()) - lastRelativeEnd]); + +          // Encode the element.            elementDecoder.encode(element, byteWriter); + +          // Record the framing offset of the element.            var relativeEnd = byteWriter.position() - startOffset;            framingOffsets.add(relativeEnd); - -          // Align the next element. -          byteWriter.write(new byte[align(relativeEnd, alignment()) - relativeEnd]);          }          // Write the framing offsets. @@ -710,21 +715,30 @@ public abstract class Decoder<T> {      @Override      @SuppressWarnings("unchecked")      void encode(Object[] value, ByteWriter byteWriter) { +      // The unit type is encoded as a single zero byte. +      if (value.length == 0) { +        byteWriter.write((byte) 0); +        return; +      } +        int startOffset = byteWriter.position();        ArrayList<Integer> framingOffsets = new ArrayList<>(value.length);        for (int i = 0; i < value.length; ++i) {          var componentDecoder = (Decoder<Object>) componentDecoders[i]; -        componentDecoder.encode(value[i], byteWriter); -        var relativeEnd = byteWriter.position() - startOffset; +        // Align the element. +        var lastRelativeEnd = byteWriter.position() - startOffset; +        byteWriter.write(new byte[align(lastRelativeEnd, componentDecoder.alignment()) - lastRelativeEnd]); + +        // Encode the element. +        componentDecoder.encode(value[i], byteWriter); +        // Record the framing offset of the element if it is of variable size.          var fixedComponentSize = componentDecoders[i].fixedSize();          if (fixedComponentSize == null && i < value.length - 1) { +          var relativeEnd = byteWriter.position() - startOffset;            framingOffsets.add(relativeEnd);          } - -        // Align the next element. -        byteWriter.write(new byte[align(relativeEnd, alignment()) - relativeEnd]);        }        // Write the framing offsets in reverse order. @@ -732,6 +746,12 @@ public abstract class Decoder<T> {        for (int i = framingOffsets.size() - 1; i >= 0; --i) {          byteWriter.writeIntN(framingOffsets.get(i), framingOffsetSize);        } + +      // Pad the structure to its alignment if it is of fixed size. +      if (fixedSize() != null) { +        var lastRelativeEnd = byteWriter.position() - startOffset; +        byteWriter.write(new byte[align(lastRelativeEnd, alignment()) - lastRelativeEnd]); +      }      }    } @@ -975,7 +995,7 @@ public abstract class Decoder<T> {      @Override      void encode(String value, ByteWriter byteWriter) { -      byteWriter.write(charset.encode(value)); +      byteWriter.write(charset.encode(value).rewind());        byteWriter.write((byte) 0);      }    } @@ -1044,7 +1064,7 @@ public abstract class Decoder<T> {        var innerByteWriter = new ByteWriter();        Decoder.this.encode(value, innerByteWriter);        var transformedBuffer = encodingFunction.apply(innerByteWriter.toByteBuffer()); -      byteWriter.write(transformedBuffer); +      byteWriter.write(transformedBuffer.rewind());      }    } @@ -1136,7 +1156,7 @@ public abstract class Decoder<T> {    }    private static class ByteWriter { -    private ByteOrder byteOrder = ByteOrder.nativeOrder(); +    private ByteOrder byteOrder = BIG_ENDIAN;      private final ByteArrayOutputStream outputStream;      ByteWriter() { @@ -1167,19 +1187,19 @@ public abstract class Decoder<T> {      }      void write(int value) { -      write(ByteBuffer.allocate(4).order(byteOrder).putInt(value)); +      write(ByteBuffer.allocate(4).order(byteOrder).putInt(value).rewind());      }      void write(long value) { -      write(ByteBuffer.allocate(8).order(byteOrder).putLong(value)); +      write(ByteBuffer.allocate(8).order(byteOrder).putLong(value).rewind());      }      void write(short value) { -      write(ByteBuffer.allocate(2).order(byteOrder).putShort(value)); +      write(ByteBuffer.allocate(2).order(byteOrder).putShort(value).rewind());      }      void write(double value) { -      write(ByteBuffer.allocate(8).order(byteOrder).putDouble(value)); +      write(ByteBuffer.allocate(8).order(byteOrder).putDouble(value).rewind());      }      private void writeIntN(int value, int byteCount) { @@ -1195,7 +1215,7 @@ public abstract class Decoder<T> {            default ->              throw new IllegalArgumentException("invalid byte count: %d".formatted(byteCount));          } -      write(byteBuffer); +      write(byteBuffer.rewind());      }      ByteWriter duplicate() { | 
