blob: 6edf2174f6d0bab64dbcd40c3b3fab2672419b0c [file] [log] [blame]
Matthias Andreas Benkardb5d657a2022-02-03 21:14:30 +01001// SPDX-FileCopyrightText: © 2021 Matthias Andreas Benkard <code@mail.matthias.benkard.de>
2//
3// SPDX-License-Identifier: LGPL-3.0-or-later
4
Matthias Andreas Benkard05114642021-12-29 21:51:29 +01005package eu.mulk.jgvariant.ostree;
6
Matthias Andreas Benkardc981cde2021-12-30 20:37:39 +01007import java.nio.ByteBuffer;
Matthias Andreas Benkard05114642021-12-29 21:51:29 +01008
9/** An operation in a static delta. */
Matthias Andreas Benkardc981cde2021-12-30 20:37:39 +010010public sealed interface DeltaOperation {
Matthias Andreas Benkard05114642021-12-29 21:51:29 +010011
Matthias Andreas Benkardc981cde2021-12-30 20:37:39 +010012 record OpenSpliceAndCloseMeta(long offset, long size) implements DeltaOperation {}
Matthias Andreas Benkard05114642021-12-29 21:51:29 +010013
Matthias Andreas Benkardc981cde2021-12-30 20:37:39 +010014 record OpenSpliceAndCloseReal(long offset, long size, long modeOffset, long xattrOffset)
15 implements DeltaOperation {}
Matthias Andreas Benkard05114642021-12-29 21:51:29 +010016
Matthias Andreas Benkardc981cde2021-12-30 20:37:39 +010017 record Open(long size, long modeOffset, long xattrOffset) implements DeltaOperation {}
Matthias Andreas Benkard05114642021-12-29 21:51:29 +010018
Matthias Andreas Benkardc981cde2021-12-30 20:37:39 +010019 record Write(long offset, long size) implements DeltaOperation {}
20
21 record SetReadSource(long offset) implements DeltaOperation {}
22
23 record UnsetReadSource() implements DeltaOperation {}
24
25 record Close() implements DeltaOperation {}
26
27 record BsPatch(long offset, long size) implements DeltaOperation {}
28
29 static DeltaOperation readFrom(ByteBuffer byteBuffer, ObjectType objectType) {
30 byte opcode = byteBuffer.get();
31 return switch (DeltaOperationType.valueOf(opcode)) {
32 case OPEN_SPLICE_AND_CLOSE -> {
33 if (objectType == ObjectType.FILE || objectType == ObjectType.PAYLOAD_LINK) {
34 long modeOffset = readVarint64(byteBuffer);
35 long xattrOffset = readVarint64(byteBuffer);
36 long size = readVarint64(byteBuffer);
37 long offset = readVarint64(byteBuffer);
38 yield new OpenSpliceAndCloseReal(offset, size, modeOffset, xattrOffset);
39 } else {
40 long size = readVarint64(byteBuffer);
41 long offset = readVarint64(byteBuffer);
42 yield new OpenSpliceAndCloseMeta(offset, size);
43 }
44 }
45 case OPEN -> {
46 long modeOffset = readVarint64(byteBuffer);
47 long xattrOffset = readVarint64(byteBuffer);
48 long size = readVarint64(byteBuffer);
49 yield new Open(size, modeOffset, xattrOffset);
50 }
51 case WRITE -> {
52 long size = readVarint64(byteBuffer);
53 long offset = readVarint64(byteBuffer);
54 yield new Write(offset, size);
55 }
56 case SET_READ_SOURCE -> {
57 long offset = readVarint64(byteBuffer);
58 yield new SetReadSource(offset);
59 }
60 case UNSET_READ_SOURCE -> new UnsetReadSource();
61 case CLOSE -> new Close();
62 case BSPATCH -> {
63 long offset = readVarint64(byteBuffer);
64 long size = readVarint64(byteBuffer);
65 yield new BsPatch(offset, size);
66 }
Matthias Andreas Benkard05114642021-12-29 21:51:29 +010067 };
68 }
Matthias Andreas Benkardc981cde2021-12-30 20:37:39 +010069
70 /**
71 * Reads a Protobuf varint from a byte buffer.
72 *
73 * <p>Varint64 encoding is little-endian and works by using the lower 7 bits of each byte as the
74 * payload and the 0x80 bit as an indicator of whether the varint continues.
75 */
76 private static long readVarint64(ByteBuffer byteBuffer) {
77 long acc = 0L;
78
79 for (int i = 0; i < 10; ++i) {
80 long b = byteBuffer.get();
81 acc |= (b & 0x7F) << (i * 7);
82 if ((b & 0x80) == 0) {
83 break;
84 }
85 }
86
87 return acc;
88 }
Matthias Andreas Benkard05114642021-12-29 21:51:29 +010089}