blob: 73cb67c8313ff1c9a24667972a22033e8a337a0e [file] [log] [blame]
Matthias Andreas Benkard05114642021-12-29 21:51:29 +01001package eu.mulk.jgvariant.ostree;
2
Matthias Andreas Benkardc981cde2021-12-30 20:37:39 +01003import java.nio.ByteBuffer;
Matthias Andreas Benkard05114642021-12-29 21:51:29 +01004
5/** An operation in a static delta. */
Matthias Andreas Benkardc981cde2021-12-30 20:37:39 +01006public sealed interface DeltaOperation {
Matthias Andreas Benkard05114642021-12-29 21:51:29 +01007
Matthias Andreas Benkardc981cde2021-12-30 20:37:39 +01008 record OpenSpliceAndCloseMeta(long offset, long size) implements DeltaOperation {}
Matthias Andreas Benkard05114642021-12-29 21:51:29 +01009
Matthias Andreas Benkardc981cde2021-12-30 20:37:39 +010010 record OpenSpliceAndCloseReal(long offset, long size, long modeOffset, long xattrOffset)
11 implements DeltaOperation {}
Matthias Andreas Benkard05114642021-12-29 21:51:29 +010012
Matthias Andreas Benkardc981cde2021-12-30 20:37:39 +010013 record Open(long size, long modeOffset, long xattrOffset) implements DeltaOperation {}
Matthias Andreas Benkard05114642021-12-29 21:51:29 +010014
Matthias Andreas Benkardc981cde2021-12-30 20:37:39 +010015 record Write(long offset, long size) implements DeltaOperation {}
16
17 record SetReadSource(long offset) implements DeltaOperation {}
18
19 record UnsetReadSource() implements DeltaOperation {}
20
21 record Close() implements DeltaOperation {}
22
23 record BsPatch(long offset, long size) implements DeltaOperation {}
24
25 static DeltaOperation readFrom(ByteBuffer byteBuffer, ObjectType objectType) {
26 byte opcode = byteBuffer.get();
27 return switch (DeltaOperationType.valueOf(opcode)) {
28 case OPEN_SPLICE_AND_CLOSE -> {
29 if (objectType == ObjectType.FILE || objectType == ObjectType.PAYLOAD_LINK) {
30 long modeOffset = readVarint64(byteBuffer);
31 long xattrOffset = readVarint64(byteBuffer);
32 long size = readVarint64(byteBuffer);
33 long offset = readVarint64(byteBuffer);
34 yield new OpenSpliceAndCloseReal(offset, size, modeOffset, xattrOffset);
35 } else {
36 long size = readVarint64(byteBuffer);
37 long offset = readVarint64(byteBuffer);
38 yield new OpenSpliceAndCloseMeta(offset, size);
39 }
40 }
41 case OPEN -> {
42 long modeOffset = readVarint64(byteBuffer);
43 long xattrOffset = readVarint64(byteBuffer);
44 long size = readVarint64(byteBuffer);
45 yield new Open(size, modeOffset, xattrOffset);
46 }
47 case WRITE -> {
48 long size = readVarint64(byteBuffer);
49 long offset = readVarint64(byteBuffer);
50 yield new Write(offset, size);
51 }
52 case SET_READ_SOURCE -> {
53 long offset = readVarint64(byteBuffer);
54 yield new SetReadSource(offset);
55 }
56 case UNSET_READ_SOURCE -> new UnsetReadSource();
57 case CLOSE -> new Close();
58 case BSPATCH -> {
59 long offset = readVarint64(byteBuffer);
60 long size = readVarint64(byteBuffer);
61 yield new BsPatch(offset, size);
62 }
Matthias Andreas Benkard05114642021-12-29 21:51:29 +010063 };
64 }
Matthias Andreas Benkardc981cde2021-12-30 20:37:39 +010065
66 /**
67 * Reads a Protobuf varint from a byte buffer.
68 *
69 * <p>Varint64 encoding is little-endian and works by using the lower 7 bits of each byte as the
70 * payload and the 0x80 bit as an indicator of whether the varint continues.
71 */
72 private static long readVarint64(ByteBuffer byteBuffer) {
73 long acc = 0L;
74
75 for (int i = 0; i < 10; ++i) {
76 long b = byteBuffer.get();
77 acc |= (b & 0x7F) << (i * 7);
78 if ((b & 0x80) == 0) {
79 break;
80 }
81 }
82
83 return acc;
84 }
Matthias Andreas Benkard05114642021-12-29 21:51:29 +010085}