Matthias Andreas Benkard | b5d657a | 2022-02-03 21:14:30 +0100 | [diff] [blame^] | 1 | // SPDX-FileCopyrightText: © 2021 Matthias Andreas Benkard <code@mail.matthias.benkard.de> |
| 2 | // |
| 3 | // SPDX-License-Identifier: LGPL-3.0-or-later |
| 4 | |
Matthias Andreas Benkard | 0511464 | 2021-12-29 21:51:29 +0100 | [diff] [blame] | 5 | package eu.mulk.jgvariant.ostree; |
| 6 | |
Matthias Andreas Benkard | c981cde | 2021-12-30 20:37:39 +0100 | [diff] [blame] | 7 | import java.nio.ByteBuffer; |
Matthias Andreas Benkard | 0511464 | 2021-12-29 21:51:29 +0100 | [diff] [blame] | 8 | |
| 9 | /** An operation in a static delta. */ |
Matthias Andreas Benkard | c981cde | 2021-12-30 20:37:39 +0100 | [diff] [blame] | 10 | public sealed interface DeltaOperation { |
Matthias Andreas Benkard | 0511464 | 2021-12-29 21:51:29 +0100 | [diff] [blame] | 11 | |
Matthias Andreas Benkard | c981cde | 2021-12-30 20:37:39 +0100 | [diff] [blame] | 12 | record OpenSpliceAndCloseMeta(long offset, long size) implements DeltaOperation {} |
Matthias Andreas Benkard | 0511464 | 2021-12-29 21:51:29 +0100 | [diff] [blame] | 13 | |
Matthias Andreas Benkard | c981cde | 2021-12-30 20:37:39 +0100 | [diff] [blame] | 14 | record OpenSpliceAndCloseReal(long offset, long size, long modeOffset, long xattrOffset) |
| 15 | implements DeltaOperation {} |
Matthias Andreas Benkard | 0511464 | 2021-12-29 21:51:29 +0100 | [diff] [blame] | 16 | |
Matthias Andreas Benkard | c981cde | 2021-12-30 20:37:39 +0100 | [diff] [blame] | 17 | record Open(long size, long modeOffset, long xattrOffset) implements DeltaOperation {} |
Matthias Andreas Benkard | 0511464 | 2021-12-29 21:51:29 +0100 | [diff] [blame] | 18 | |
Matthias Andreas Benkard | c981cde | 2021-12-30 20:37:39 +0100 | [diff] [blame] | 19 | 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 Benkard | 0511464 | 2021-12-29 21:51:29 +0100 | [diff] [blame] | 67 | }; |
| 68 | } |
Matthias Andreas Benkard | c981cde | 2021-12-30 20:37:39 +0100 | [diff] [blame] | 69 | |
| 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 Benkard | 0511464 | 2021-12-29 21:51:29 +0100 | [diff] [blame] | 89 | } |