blob: 3a8185c033179ba110e1183c51fa265a0813a0de [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;
8import java.util.Arrays;
Matthias Andreas Benkardc7aa2b62022-01-23 18:10:03 +01009import java.util.Base64;
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +010010import java.util.HexFormat;
Matthias Andreas Benkard05114642021-12-29 21:51:29 +010011import java.util.stream.IntStream;
12import java.util.stream.Stream;
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +010013
14/**
15 * A wrapper for a {@code byte[]} that implements {@link #equals(Object)}, {@link #hashCode()}, and
16 * {@link #toString()} according to value semantics.
Matthias Andreas Benkard05114642021-12-29 21:51:29 +010017 *
18 * @param bytes the byte array that this ByteString wraps.
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +010019 */
20public record ByteString(byte[] bytes) {
21
22 private static final Decoder<ByteString> DECODER = Decoder.ofByteArray().map(ByteString::new);
23
Matthias Andreas Benkard05114642021-12-29 21:51:29 +010024 /**
25 * Returns a decoder for a {@code byte[]} that wraps the result in {@link ByteString}.
26 *
27 * @return a possibly shared {@link Decoder}.
28 */
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +010029 public static Decoder<ByteString> decoder() {
30 return DECODER;
31 }
32
33 @Override
34 public boolean equals(Object o) {
35 return (o instanceof ByteString byteString) && Arrays.equals(bytes, byteString.bytes);
36 }
37
38 @Override
39 public int hashCode() {
40 return Arrays.hashCode(bytes);
41 }
42
43 @Override
44 public String toString() {
45 return "ByteString{hex=\"%s\"}".formatted(hex());
46 }
47
Matthias Andreas Benkard05114642021-12-29 21:51:29 +010048 /**
49 * Converts the contained byte array into a hex string.
50 *
51 * <p>Useful for printing.
52 *
53 * @return a hex string representation of this byte string.
54 */
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +010055 public String hex() {
56 return HexFormat.of().formatHex(bytes);
57 }
58
Matthias Andreas Benkard05114642021-12-29 21:51:29 +010059 /**
60 * Parses a hex string into a {@link ByteString}.
61 *
62 * @param hex a hex string.
63 * @return a {@link ByteString} corresponding to the given hex string.
64 */
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +010065 public static ByteString ofHex(String hex) {
66 return new ByteString(HexFormat.of().parseHex(hex));
67 }
Matthias Andreas Benkard05114642021-12-29 21:51:29 +010068
69 /**
Matthias Andreas Benkardc7aa2b62022-01-23 18:10:03 +010070 * Converts the contained byte array into modified Base64 (with {@code "/"} replaced with {@code
71 * "-"}).
72 *
73 * <p>Modified Base64 is Base64 with {@code "/"} replaced with {@code "_"}. It is used to address
74 * static deltas in an OSTree repository.
75 *
76 * <p>Useful for printing.
77 *
78 * @return a modified Base64 representation of the bytes making up this checksum.
79 */
80 public String modifiedBase64() {
81 return Base64.getEncoder().withoutPadding().encodeToString(bytes).replace('/', '_');
82 }
83
84 /**
85 * Parses a modified Base64 string into a {@link Checksum}.
86 *
87 * <p>Modified Base64 is Base64 with {@code "/"} replaced with {@code "_"}. It is used to address
88 * static deltas in an OSTree repository.
89 *
90 * @param mbase64 a hex string.
91 * @return a {@link Checksum} corresponding to the given modified Base64 string.
92 */
93 public static ByteString ofModifiedBase64(String mbase64) {
94 return new ByteString(Base64.getDecoder().decode(mbase64.replace('_', '/')));
95 }
96
97 /**
Matthias Andreas Benkard05114642021-12-29 21:51:29 +010098 * Returns the number of bytes in the byte string.
99 *
100 * @return the number of bytes in the byte string.
101 */
102 public int size() {
103 return bytes.length;
104 }
105
106 /**
107 * Returns a {@link Stream} of all the bytes in the byte string.
108 *
109 * @return a new {@link Stream}.
110 */
111 Stream<Byte> stream() {
112 return IntStream.range(0, bytes.length).mapToObj(i -> bytes[i]);
113 }
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +0100114}