blob: e9bdf841ef1144bf4e302c3a65feb9c5738debdd [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 Benkard4e8423d2021-12-19 22:56:09 +01005package eu.mulk.jgvariant.ostree;
6
7import eu.mulk.jgvariant.core.Decoder;
Matthias Andreas Benkard05114642021-12-29 21:51:29 +01008import java.nio.ByteBuffer;
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +01009
10/**
11 * A wrapper for {@link ByteString} that refers to a content-addressed object in an OSTree
12 * repository.
Matthias Andreas Benkard05114642021-12-29 21:51:29 +010013 *
14 * @param byteString the bytes that make up this {@link Checksum}.
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +010015 */
Matthias Andreas Benkard05114642021-12-29 21:51:29 +010016public record Checksum(ByteString byteString) {
17
18 private static final int SIZE = 32;
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +010019
Matthias Andreas Benkardaa11d822023-12-10 09:20:48 +010020 private static final Decoder<Checksum> DECODER =
Matthias Andreas Benkardc442ebe2023-12-10 17:58:38 +010021 ByteString.decoder().map(Checksum::new, Checksum::optimizedByteString);
22
23 private static final ByteString NULL_BYTESTRING = new ByteString(new byte[0]);
24
25 private static final Checksum ZERO = new Checksum(new ByteString(new byte[SIZE]));
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +010026
Matthias Andreas Benkard05114642021-12-29 21:51:29 +010027 public Checksum {
Matthias Andreas Benkardf96d0e32021-12-29 21:53:50 +010028 if (byteString.size() == 0) {
29 byteString = zero().byteString;
30 }
31
Matthias Andreas Benkard05114642021-12-29 21:51:29 +010032 if (byteString.size() != SIZE) {
33 throw new IllegalArgumentException(
34 "attempted to construct Checksum of length %d (expected: %d)"
35 .formatted(byteString.size(), SIZE));
36 }
37 }
38
39 /**
40 * A decoder for a {@code byte[]} that wraps the result in a {@link Checksum}.
41 *
42 * @return a possibly shared {@link Decoder}.
43 */
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +010044 public static Decoder<Checksum> decoder() {
45 return DECODER;
46 }
47
Matthias Andreas Benkard05114642021-12-29 21:51:29 +010048 /**
49 * Returns an empty checksum.
50 *
51 * @return a checksum whose bits are all zero.
52 */
53 public static Checksum zero() {
Matthias Andreas Benkardc442ebe2023-12-10 17:58:38 +010054 return ZERO;
55 }
56
57 public ByteString optimizedByteString() {
58 return isEmpty() ? NULL_BYTESTRING : byteString;
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +010059 }
60
Matthias Andreas Benkard05114642021-12-29 21:51:29 +010061 /**
62 * Checks whether the checksum contains only zero bits.
63 *
64 * @return {@code true} if the byte string is equal to {@link #zero()}, {@code false} otherwise.
65 */
66 public boolean isEmpty() {
Matthias Andreas Benkardc442ebe2023-12-10 17:58:38 +010067 return equals(ZERO);
Matthias Andreas Benkard05114642021-12-29 21:51:29 +010068 }
69
70 /**
71 * Converts the contained byte array into a hex string.
72 *
73 * <p>Useful for printing.
74 *
75 * @return a hex string representation of the bytes making up this checksum.
76 */
77 public String hex() {
78 return byteString.hex();
79 }
80
81 /**
82 * Parses a hex string into a {@link Checksum}.
83 *
84 * @param hex a hex string.
85 * @return a {@link Checksum} corresponding to the given hex string.
86 */
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +010087 public static Checksum ofHex(String hex) {
88 return new Checksum(ByteString.ofHex(hex));
89 }
Matthias Andreas Benkard05114642021-12-29 21:51:29 +010090
91 /**
Matthias Andreas Benkardc7aa2b62022-01-23 18:10:03 +010092 * Converts the contained byte array into modified Base64 (with {@code "/"} replaced with {@code
93 * "-"}).
94 *
95 * <p>Modified Base64 is Base64 with {@code "/"} replaced with {@code "_"}. It is used to address
96 * static deltas in an OSTree repository.
97 *
98 * <p>Useful for printing.
99 *
100 * @return a modified Base64 representation of the bytes making up this checksum.
101 */
102 public String modifiedBase64() {
103 return byteString.modifiedBase64();
104 }
105
106 /**
107 * Parses a modified Base64 string into a {@link Checksum}.
108 *
109 * <p>Modified Base64 is Base64 with {@code "/"} replaced with {@code "_"}. It is used to address
110 * static deltas in an OSTree repository.
111 *
112 * @param mbase64 a hex string.
113 * @return a {@link Checksum} corresponding to the given modified Base64 string.
114 */
115 public static Checksum ofModifiedBase64(String mbase64) {
116 return new Checksum(ByteString.ofModifiedBase64(mbase64));
117 }
118
119 /**
Matthias Andreas Benkard05114642021-12-29 21:51:29 +0100120 * Reads a Checksum for a {@link ByteBuffer}.
121 *
122 * @param byteBuffer the byte buffer to read from.
123 * @return a checksum.
124 */
125 public static Checksum readFrom(ByteBuffer byteBuffer) {
126 var bytes = new byte[SIZE];
127 byteBuffer.get(bytes);
128 return new Checksum(new ByteString(bytes));
129 }
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +0100130}