blob: bb8cbb67bd330aadfeb41a4c53b05a5d75ffb0e7 [file] [log] [blame]
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +01001package eu.mulk.jgvariant.ostree;
2
3import eu.mulk.jgvariant.core.Decoder;
4import java.util.Arrays;
Matthias Andreas Benkardc7aa2b62022-01-23 18:10:03 +01005import java.util.Base64;
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +01006import java.util.HexFormat;
Matthias Andreas Benkard05114642021-12-29 21:51:29 +01007import java.util.stream.IntStream;
8import java.util.stream.Stream;
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +01009
10/**
11 * A wrapper for a {@code byte[]} that implements {@link #equals(Object)}, {@link #hashCode()}, and
12 * {@link #toString()} according to value semantics.
Matthias Andreas Benkard05114642021-12-29 21:51:29 +010013 *
14 * @param bytes the byte array that this ByteString wraps.
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +010015 */
16public record ByteString(byte[] bytes) {
17
18 private static final Decoder<ByteString> DECODER = Decoder.ofByteArray().map(ByteString::new);
19
Matthias Andreas Benkard05114642021-12-29 21:51:29 +010020 /**
21 * Returns a decoder for a {@code byte[]} that wraps the result in {@link ByteString}.
22 *
23 * @return a possibly shared {@link Decoder}.
24 */
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +010025 public static Decoder<ByteString> decoder() {
26 return DECODER;
27 }
28
29 @Override
30 public boolean equals(Object o) {
31 return (o instanceof ByteString byteString) && Arrays.equals(bytes, byteString.bytes);
32 }
33
34 @Override
35 public int hashCode() {
36 return Arrays.hashCode(bytes);
37 }
38
39 @Override
40 public String toString() {
41 return "ByteString{hex=\"%s\"}".formatted(hex());
42 }
43
Matthias Andreas Benkard05114642021-12-29 21:51:29 +010044 /**
45 * Converts the contained byte array into a hex string.
46 *
47 * <p>Useful for printing.
48 *
49 * @return a hex string representation of this byte string.
50 */
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +010051 public String hex() {
52 return HexFormat.of().formatHex(bytes);
53 }
54
Matthias Andreas Benkard05114642021-12-29 21:51:29 +010055 /**
56 * Parses a hex string into a {@link ByteString}.
57 *
58 * @param hex a hex string.
59 * @return a {@link ByteString} corresponding to the given hex string.
60 */
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +010061 public static ByteString ofHex(String hex) {
62 return new ByteString(HexFormat.of().parseHex(hex));
63 }
Matthias Andreas Benkard05114642021-12-29 21:51:29 +010064
65 /**
Matthias Andreas Benkardc7aa2b62022-01-23 18:10:03 +010066 * Converts the contained byte array into modified Base64 (with {@code "/"} replaced with {@code
67 * "-"}).
68 *
69 * <p>Modified Base64 is Base64 with {@code "/"} replaced with {@code "_"}. It is used to address
70 * static deltas in an OSTree repository.
71 *
72 * <p>Useful for printing.
73 *
74 * @return a modified Base64 representation of the bytes making up this checksum.
75 */
76 public String modifiedBase64() {
77 return Base64.getEncoder().withoutPadding().encodeToString(bytes).replace('/', '_');
78 }
79
80 /**
81 * Parses a modified Base64 string into a {@link Checksum}.
82 *
83 * <p>Modified Base64 is Base64 with {@code "/"} replaced with {@code "_"}. It is used to address
84 * static deltas in an OSTree repository.
85 *
86 * @param mbase64 a hex string.
87 * @return a {@link Checksum} corresponding to the given modified Base64 string.
88 */
89 public static ByteString ofModifiedBase64(String mbase64) {
90 return new ByteString(Base64.getDecoder().decode(mbase64.replace('_', '/')));
91 }
92
93 /**
Matthias Andreas Benkard05114642021-12-29 21:51:29 +010094 * Returns the number of bytes in the byte string.
95 *
96 * @return the number of bytes in the byte string.
97 */
98 public int size() {
99 return bytes.length;
100 }
101
102 /**
103 * Returns a {@link Stream} of all the bytes in the byte string.
104 *
105 * @return a new {@link Stream}.
106 */
107 Stream<Byte> stream() {
108 return IntStream.range(0, bytes.length).mapToObj(i -> bytes[i]);
109 }
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +0100110}