jgvariant-ostree: Handle non-canonical endianness in static deltas.

Change-Id: I333fce6d6f4df995d6d965261bb66e50c116f02d
diff --git a/jgvariant-ostree/src/main/java/eu/mulk/jgvariant/ostree/DeltaFallback.java b/jgvariant-ostree/src/main/java/eu/mulk/jgvariant/ostree/DeltaFallback.java
index 46470d4..0967043 100644
--- a/jgvariant-ostree/src/main/java/eu/mulk/jgvariant/ostree/DeltaFallback.java
+++ b/jgvariant-ostree/src/main/java/eu/mulk/jgvariant/ostree/DeltaFallback.java
@@ -23,15 +23,21 @@
           DeltaFallback.class,
           Decoder.ofByte().map(ObjectType::valueOf),
           Checksum.decoder(),
-          Decoder.ofLong().withByteOrder(ByteOrder.LITTLE_ENDIAN), // FIXME: non-canonical
-          Decoder.ofLong().withByteOrder(ByteOrder.LITTLE_ENDIAN)); // FIXME: non-canonical
+          Decoder.ofLong(),
+          Decoder.ofLong());
 
   /**
    * Acquires a {@link Decoder} for the enclosing type.
    *
+   * <p><strong>Note:</strong> This decoder has an unspecified {@link ByteOrder}.
+   *
    * @return a possibly shared {@link Decoder}.
    */
   public static Decoder<DeltaFallback> decoder() {
     return DECODER;
   }
+
+  DeltaFallback byteSwapped() {
+    return new DeltaFallback(objectType, checksum, compressedSize, uncompressedSize);
+  }
 }
diff --git a/jgvariant-ostree/src/main/java/eu/mulk/jgvariant/ostree/DeltaMetaEntry.java b/jgvariant-ostree/src/main/java/eu/mulk/jgvariant/ostree/DeltaMetaEntry.java
index 0eaea73..7269a80 100644
--- a/jgvariant-ostree/src/main/java/eu/mulk/jgvariant/ostree/DeltaMetaEntry.java
+++ b/jgvariant-ostree/src/main/java/eu/mulk/jgvariant/ostree/DeltaMetaEntry.java
@@ -49,10 +49,10 @@
   private static final Decoder<DeltaMetaEntry> DECODER =
       Decoder.ofStructure(
           DeltaMetaEntry.class,
-          Decoder.ofInt().withByteOrder(ByteOrder.LITTLE_ENDIAN), // FIXME: non-canonical
+          Decoder.ofInt(),
           Checksum.decoder(),
-          Decoder.ofLong().withByteOrder(ByteOrder.LITTLE_ENDIAN), // FIXME: non-canonical
-          Decoder.ofLong().withByteOrder(ByteOrder.LITTLE_ENDIAN), // FIXME: non-canonical
+          Decoder.ofLong(),
+          Decoder.ofLong(),
           Decoder.ofByteArray().map(DeltaMetaEntry::parseObjectList));
 
   private static List<DeltaObject> parseObjectList(byte[] bytes) {
@@ -71,9 +71,16 @@
   /**
    * Acquires a {@link Decoder} for the enclosing type.
    *
+   * <p><strong>Note:</strong> This decoder has an unspecified {@link ByteOrder}.
+   *
    * @return a possibly shared {@link Decoder}.
    */
   public static Decoder<DeltaMetaEntry> decoder() {
     return DECODER;
   }
+
+  DeltaMetaEntry byteSwapped() {
+    // FIXME
+    return new DeltaMetaEntry(version, checksum, compressedSize, uncompressedSize, objects);
+  }
 }
diff --git a/jgvariant-ostree/src/main/java/eu/mulk/jgvariant/ostree/DeltaSuperblock.java b/jgvariant-ostree/src/main/java/eu/mulk/jgvariant/ostree/DeltaSuperblock.java
index edcf2bf..10b1661 100644
--- a/jgvariant-ostree/src/main/java/eu/mulk/jgvariant/ostree/DeltaSuperblock.java
+++ b/jgvariant-ostree/src/main/java/eu/mulk/jgvariant/ostree/DeltaSuperblock.java
@@ -57,15 +57,41 @@
 
   private static final Decoder<DeltaSuperblock> DECODER =
       Decoder.ofStructure(
-          DeltaSuperblock.class,
-          Metadata.decoder(),
-          Decoder.ofLong().withByteOrder(ByteOrder.BIG_ENDIAN),
-          Checksum.decoder(),
-          Checksum.decoder(),
-          Commit.decoder(),
-          Decoder.ofByteArray().map(DeltaSuperblock::parseDeltaNameList),
-          Decoder.ofArray(DeltaMetaEntry.decoder()),
-          Decoder.ofArray(DeltaFallback.decoder()));
+              DeltaSuperblock.class,
+              Metadata.decoder(),
+              Decoder.ofLong().withByteOrder(ByteOrder.BIG_ENDIAN),
+              Checksum.decoder(),
+              Checksum.decoder(),
+              Commit.decoder(),
+              Decoder.ofByteArray().map(DeltaSuperblock::parseDeltaNameList),
+              Decoder.ofArray(DeltaMetaEntry.decoder()).withByteOrder(ByteOrder.LITTLE_ENDIAN),
+              Decoder.ofArray(DeltaFallback.decoder()).withByteOrder(ByteOrder.LITTLE_ENDIAN))
+          .map(
+              deltaSuperblock -> {
+                // Fix up the endianness of the 'entries' and 'fallbacks' fields, which have
+                // unspecified byte order.
+                var endiannessMetadatum =
+                    deltaSuperblock.metadata().fields().get("ostree.endianness");
+                if (endiannessMetadatum != null
+                    && endiannessMetadatum.value() instanceof Byte endiannessByte
+                    && endiannessByte == (byte) 'B') {
+                  return deltaSuperblock.byteSwapped();
+                } else {
+                  return deltaSuperblock;
+                }
+              });
+
+  private DeltaSuperblock byteSwapped() {
+    return new DeltaSuperblock(
+        metadata,
+        timestamp,
+        fromChecksum,
+        toChecksum,
+        commit,
+        dependencies,
+        entries.stream().map(DeltaMetaEntry::byteSwapped).toList(),
+        fallbacks.stream().map(DeltaFallback::byteSwapped).toList());
+  }
 
   private static List<DeltaName> parseDeltaNameList(byte[] bytes) {
     var byteBuffer = ByteBuffer.wrap(bytes);