aboutsummaryrefslogtreecommitdiff
path: root/jgvariant-ostree/src/main/java/eu/mulk/jgvariant/ostree/DeltaMetaEntry.java
blob: 0eaea73066ade40fe9156f6c4cb32af53f5ae001 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
package eu.mulk.jgvariant.ostree;

import eu.mulk.jgvariant.core.Decoder;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.List;

/**
 * An entry in a {@link DeltaSuperblock}.
 *
 * <p>Reference: {@code ostree-repo-static-delta-private.h#OSTREE_STATIC_DELTA_META_ENTRY_FORMAT}
 *
 * @param version the version corresponding to the version of {@link DeltaPartPayload}; always 0.
 * @param checksum the checksum of the {@link DeltaPartPayload}.
 * @param compressedSize the total compressed size of the delta.
 * @param uncompressedSize the total uncompressed size of the files generated by the delta.
 * @param objects a list of objects generated by the delta payload.
 */
public record DeltaMetaEntry(
    int version,
    Checksum checksum,
    long compressedSize,
    long uncompressedSize,
    List<DeltaObject> objects) {

  /**
   * A reference to an object generated by a {@link DeltaPartPayload}.
   *
   * @param objectType the file type.
   * @param checksum the checksum of the resulting file.
   */
  public record DeltaObject(ObjectType objectType, Checksum checksum) {

    private static final Decoder<DeltaObject> DECODER =
        Decoder.ofStructure(
            DeltaObject.class, Decoder.ofByte().map(ObjectType::valueOf), Checksum.decoder());

    /**
     * Acquires a {@link Decoder} for the enclosing type.
     *
     * @return a possibly shared {@link Decoder}.
     */
    public static Decoder<DeltaObject> decoder() {
      return DECODER;
    }
  }

  private static final Decoder<DeltaMetaEntry> DECODER =
      Decoder.ofStructure(
          DeltaMetaEntry.class,
          Decoder.ofInt().withByteOrder(ByteOrder.LITTLE_ENDIAN), // FIXME: non-canonical
          Checksum.decoder(),
          Decoder.ofLong().withByteOrder(ByteOrder.LITTLE_ENDIAN), // FIXME: non-canonical
          Decoder.ofLong().withByteOrder(ByteOrder.LITTLE_ENDIAN), // FIXME: non-canonical
          Decoder.ofByteArray().map(DeltaMetaEntry::parseObjectList));

  private static List<DeltaObject> parseObjectList(byte[] bytes) {
    var byteBuffer = ByteBuffer.wrap(bytes);
    List<DeltaObject> objects = new ArrayList<>();

    while (byteBuffer.hasRemaining()) {
      var type = ObjectType.valueOf(byteBuffer.get());
      var checksum = Checksum.readFrom(byteBuffer);
      objects.add(new DeltaObject(type, checksum));
    }

    return objects;
  }

  /**
   * Acquires a {@link Decoder} for the enclosing type.
   *
   * @return a possibly shared {@link Decoder}.
   */
  public static Decoder<DeltaMetaEntry> decoder() {
    return DECODER;
  }
}