blob: d30366e9b462d162ee0642c6285db6718a35426c [file] [log] [blame]
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +01001package eu.mulk.jgvariant.core;
2
3import static java.nio.ByteOrder.LITTLE_ENDIAN;
4
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +01005import java.lang.reflect.InvocationTargetException;
6import java.lang.reflect.RecordComponent;
7import java.nio.ByteBuffer;
8import java.nio.ByteOrder;
9import java.nio.charset.Charset;
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +010010import java.text.ParseException;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010011import java.util.ArrayList;
12import java.util.Arrays;
13import java.util.List;
14import java.util.Optional;
Matthias Andreas Benkard25b7f902021-12-17 06:02:11 +010015import org.apiguardian.api.API;
16import org.apiguardian.api.API.Status;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010017import org.jetbrains.annotations.Nullable;
18
19/**
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +010020 * Type class for decodable types.
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010021 *
22 * <p>Use the {@code of*} family of constructor methods to acquire a suitable {@link Decoder} for
23 * the type you wish to decode.
24 *
Matthias Andreas Benkard4c32c392021-12-12 21:23:53 +010025 * <p><strong>Example</strong>
26 *
27 * <p>To parse a GVariant of type {@code "a(si)"}, which is an array of pairs of {@link String} and
28 * {@code int}, you can use the following code:
29 *
30 * <pre>{@code
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +010031 * record ExampleRecord(String s, int i) {}
Matthias Andreas Benkard4c32c392021-12-12 21:23:53 +010032 *
33 * var decoder =
34 * Decoder.ofArray(
35 * Decoder.ofStructure(
36 * ExampleRecord.class,
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +010037 * Decoder.ofString(UTF_8),
38 * Decoder.ofInt().withByteOrder(LITTLE_ENDIAN)));
Matthias Andreas Benkard4c32c392021-12-12 21:23:53 +010039 *
40 * byte[] bytes = ...;
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +010041 * List<ExampleRecord> example = decoder.decode(ByteBuffer.wrap(bytes));
Matthias Andreas Benkard4c32c392021-12-12 21:23:53 +010042 * }</pre>
43 *
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010044 * @param <T> the type that the {@link Decoder} can decode.
45 */
46@SuppressWarnings("java:S1610")
Matthias Andreas Benkard25b7f902021-12-17 06:02:11 +010047@API(status = Status.EXPERIMENTAL)
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +010048public abstract class Decoder<T> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010049
50 private Decoder() {}
51
52 /**
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +010053 * Decodes a {@link ByteBuffer} holding a serialized GVariant into a value of type {@code T}.
54 *
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010055 * @throws java.nio.BufferUnderflowException if the byte buffer is shorter than the requested
56 * data.
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +010057 * @throws IllegalArgumentException if the serialized GVariant is ill-formed
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010058 */
59 public abstract T decode(ByteBuffer byteSlice);
60
61 abstract byte alignment();
62
63 @Nullable
64 abstract Integer fixedSize();
65
66 final boolean hasFixedSize() {
67 return fixedSize() != null;
68 }
69
Matthias Andreas Benkard4c32c392021-12-12 21:23:53 +010070 /**
71 * Switches the input {@link ByteBuffer} to a given {@link ByteOrder} before reading from it.
72 *
73 * @param byteOrder the byte order to use.
74 * @return a new, decorated {@link Decoder}.
75 */
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010076 public Decoder<T> withByteOrder(ByteOrder byteOrder) {
77 var delegate = this;
78
79 return new Decoder<>() {
80 @Override
81 public byte alignment() {
82 return delegate.alignment();
83 }
84
85 @Override
86 public @Nullable Integer fixedSize() {
87 return delegate.fixedSize();
88 }
89
90 @Override
91 public T decode(ByteBuffer byteSlice) {
92 byteSlice.order(byteOrder);
93 return delegate.decode(byteSlice);
94 }
95 };
96 }
97
Matthias Andreas Benkard4c32c392021-12-12 21:23:53 +010098 /**
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +010099 * Creates a {@link Decoder} for an {@code Array} type.
Matthias Andreas Benkard4c32c392021-12-12 21:23:53 +0100100 *
101 * @param elementDecoder a {@link Decoder} for the elements of the array.
102 * @param <U> the element type.
103 * @return a new {@link Decoder}.
104 */
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100105 public static <U> Decoder<List<U>> ofArray(Decoder<U> elementDecoder) {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100106 return new ArrayDecoder<>(elementDecoder);
107 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100108
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100109 /**
110 * Creates a {@link Decoder} for a {@code Maybe} type.
111 *
112 * @param elementDecoder a {@link Decoder} for the contained element.
113 * @param <U> the element type.
114 * @return a new {@link Decoder}.
115 */
116 public static <U> Decoder<Optional<U>> ofMaybe(Decoder<U> elementDecoder) {
117 return new MaybeDecoder<>(elementDecoder);
118 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100119
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100120 /**
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100121 * Creates a {@link Decoder} for a {@code Structure} type, decoding into a {@link Record}.
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100122 *
123 * @param recordType the {@link Record} type that represents the components of the structure.
124 * @param componentDecoders a {@link Decoder} for each component of the structure.
125 * @param <U> the {@link Record} type that represents the components of the structure.
126 * @return a new {@link Decoder}.
127 */
128 public static <U extends Record> Decoder<U> ofStructure(
129 Class<U> recordType, Decoder<?>... componentDecoders) {
130 return new StructureDecoder<>(recordType, componentDecoders);
131 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100132
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100133 /**
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100134 * Creates a {@link Decoder} for a {@code Structure} type, decoding into a {@link List}.
135 *
136 * <p>Prefer {@link #ofStructure(Class, Decoder[])} if possible, which is both more type-safe and
137 * more convenient.
138 *
139 * @param componentDecoders a {@link Decoder} for each component of the structure.
140 * @return a new {@link Decoder}.
141 */
142 public static Decoder<Object[]> ofStructure(Decoder<?>... componentDecoders) {
143 return new TupleDecoder(componentDecoders);
144 }
145
146 /**
Matthias Andreas Benkardb50fcd02021-12-16 20:17:20 +0100147 * Creates a {@link Decoder} for the {@link Variant} type.
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100148 *
Matthias Andreas Benkardb50fcd02021-12-16 20:17:20 +0100149 * <p>The contained {@link Object} can be of one of the following types:
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100150 *
151 * <ul>
152 * <li>{@link Boolean}
153 * <li>{@link Byte}
154 * <li>{@link Short}
155 * <li>{@link Integer}
156 * <li>{@link Long}
157 * <li>{@link String}
158 * <li>{@link Optional} (a GVariant {@code Maybe} type)
159 * <li>{@link List} (a GVariant array)
160 * <li>{@link Object[]} (a GVariant structure)
Matthias Andreas Benkardb50fcd02021-12-16 20:17:20 +0100161 * <li>{@link Variant} (a nested variant)
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100162 * </ul>
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100163 *
164 * @return a new {@link Decoder}.
165 */
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +0100166 public static Decoder<Variant> ofVariant() {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100167 return new VariantDecoder();
168 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100169
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100170 /**
Matthias Andreas Benkardb50fcd02021-12-16 20:17:20 +0100171 * Creates a {@link Decoder} for the {@code boolean} type.
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100172 *
173 * @return a new {@link Decoder}.
174 */
175 public static Decoder<Boolean> ofBoolean() {
176 return new BooleanDecoder();
177 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100178
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100179 /**
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100180 * Creates a {@link Decoder} for the 8-bit {@code byte} type.
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100181 *
182 * <p><strong>Note:</strong> It is often useful to apply {@link #withByteOrder(ByteOrder)} to the
183 * result of this method.
184 *
185 * @return a new {@link Decoder}.
186 */
187 public static Decoder<Byte> ofByte() {
188 return new ByteDecoder();
189 }
190
191 /**
192 * Creates a {@link Decoder} for the 16-bit {@code short} type.
193 *
194 * <p><strong>Note:</strong> It is often useful to apply {@link #withByteOrder(ByteOrder)} to the
195 * result of this method.
196 *
197 * @return a new {@link Decoder}.
198 */
199 public static Decoder<Short> ofShort() {
200 return new ShortDecoder();
201 }
202
203 /**
204 * Creates a {@link Decoder} for the 32-bit {@code int} type.
205 *
206 * <p><strong>Note:</strong> It is often useful to apply {@link #withByteOrder(ByteOrder)} to the
207 * result of this method.
208 *
209 * @return a new {@link Decoder}.
210 */
211 public static Decoder<Integer> ofInt() {
212 return new IntegerDecoder();
213 }
214
215 /**
216 * Creates a {@link Decoder} for the 64-bit {@code long} type.
217 *
218 * <p><strong>Note:</strong> It is often useful to apply {@link #withByteOrder(ByteOrder)} to the
219 * result of this method.
220 *
221 * @return a new {@link Decoder}.
222 */
223 public static Decoder<Long> ofLong() {
224 return new LongDecoder();
225 }
226
227 /**
228 * Creates a {@link Decoder} for the {@code double} type.
229 *
230 * @return a new {@link Decoder}.
231 */
232 public static Decoder<Double> ofDouble() {
233 return new DoubleDecoder();
234 }
235
236 /**
237 * Creates a {@link Decoder} for the {@link String} type.
238 *
239 * <p><strong>Note:</strong> While GVariant does not prescribe any particular encoding, {@link
240 * java.nio.charset.StandardCharsets#UTF_8} is the most common choice.
241 *
242 * @return a new {@link Decoder}.
243 */
244 public static Decoder<String> ofString(Charset charset) {
245 return new StringDecoder(charset);
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100246 }
247
248 private static int align(int offset, byte alignment) {
249 return offset % alignment == 0 ? offset : offset + alignment - (offset % alignment);
250 }
251
252 private static int getIntN(ByteBuffer byteSlice) {
253 var intBytes = new byte[4];
254 byteSlice.get(intBytes, 0, Math.min(4, byteSlice.limit()));
255 return ByteBuffer.wrap(intBytes).order(LITTLE_ENDIAN).getInt();
256 }
257
258 @SuppressWarnings("java:S3358")
259 private static int byteCount(int n) {
260 return n < (1 << 8) ? 1 : n < (1 << 16) ? 2 : 4;
261 }
262
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100263 private static class ArrayDecoder<U> extends Decoder<List<U>> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100264
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100265 private final Decoder<U> elementDecoder;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100266
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100267 ArrayDecoder(Decoder<U> elementDecoder) {
268 this.elementDecoder = elementDecoder;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100269 }
270
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100271 @Override
272 public byte alignment() {
273 return elementDecoder.alignment();
274 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100275
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100276 @Override
277 @Nullable
278 Integer fixedSize() {
279 return null;
280 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100281
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100282 @Override
283 public List<U> decode(ByteBuffer byteSlice) {
284 List<U> elements;
285
286 var elementSize = elementDecoder.fixedSize();
287 if (elementSize != null) {
288 // A simple C-style array.
289 elements = new ArrayList<>(byteSlice.limit() / elementSize);
290 for (int i = 0; i < byteSlice.limit(); i += elementSize) {
291 var element = elementDecoder.decode(byteSlice.slice(i, elementSize));
292 elements.add(element);
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100293 }
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100294 } else {
295 // An array with aligned elements and a vector of framing offsets in the end.
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100296 int framingOffsetSize = byteCount(byteSlice.limit());
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100297 int lastFramingOffset =
298 getIntN(byteSlice.slice(byteSlice.limit() - framingOffsetSize, framingOffsetSize));
299 int elementCount = (byteSlice.limit() - lastFramingOffset) / framingOffsetSize;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100300
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100301 elements = new ArrayList<>(elementCount);
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100302 int position = 0;
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100303 for (int i = 0; i < elementCount; i++) {
304 int framingOffset =
305 getIntN(
306 byteSlice.slice(lastFramingOffset + i * framingOffsetSize, framingOffsetSize));
307 elements.add(elementDecoder.decode(byteSlice.slice(position, framingOffset - position)));
308 position = align(framingOffset, alignment());
309 }
310 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100311
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100312 return elements;
313 }
314 }
315
316 private static class MaybeDecoder<U> extends Decoder<Optional<U>> {
317
318 private final Decoder<U> elementDecoder;
319
320 MaybeDecoder(Decoder<U> elementDecoder) {
321 this.elementDecoder = elementDecoder;
322 }
323
324 @Override
325 public byte alignment() {
326 return elementDecoder.alignment();
327 }
328
329 @Override
330 @Nullable
331 Integer fixedSize() {
332 return null;
333 }
334
335 @Override
336 public Optional<U> decode(ByteBuffer byteSlice) {
337 if (!byteSlice.hasRemaining()) {
338 return Optional.empty();
339 } else {
340 if (!elementDecoder.hasFixedSize()) {
341 // Remove trailing zero byte.
342 byteSlice.limit(byteSlice.limit() - 1);
343 }
344
345 return Optional.of(elementDecoder.decode(byteSlice));
346 }
347 }
348 }
349
350 private static class StructureDecoder<U extends Record> extends Decoder<U> {
351
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100352 private final Class<U> recordType;
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100353 private final TupleDecoder tupleDecoder;
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100354
355 StructureDecoder(Class<U> recordType, Decoder<?>... componentDecoders) {
356 var recordComponents = recordType.getRecordComponents();
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100357 if (componentDecoders.length != recordComponents.length) {
358 throw new IllegalArgumentException(
359 "number of decoders (%d) does not match number of structure components (%d)"
360 .formatted(componentDecoders.length, recordComponents.length));
361 }
362
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100363 this.recordType = recordType;
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100364 this.tupleDecoder = new TupleDecoder(componentDecoders);
365 }
366
367 @Override
368 public byte alignment() {
369 return tupleDecoder.alignment();
370 }
371
372 @Override
373 public Integer fixedSize() {
374 return tupleDecoder.fixedSize();
375 }
376
377 @Override
378 public U decode(ByteBuffer byteSlice) {
379 Object[] recordConstructorArguments = tupleDecoder.decode(byteSlice);
380
381 try {
382 var recordComponentTypes =
383 Arrays.stream(recordType.getRecordComponents())
384 .map(RecordComponent::getType)
385 .toArray(Class<?>[]::new);
386 var recordConstructor = recordType.getDeclaredConstructor(recordComponentTypes);
387 return recordConstructor.newInstance(recordConstructorArguments);
388 } catch (NoSuchMethodException
389 | InstantiationException
390 | IllegalAccessException
391 | InvocationTargetException e) {
392 throw new IllegalStateException(e);
393 }
394 }
395 }
396
397 private static class TupleDecoder extends Decoder<Object[]> {
398
399 private final Decoder<?>[] componentDecoders;
400
401 TupleDecoder(Decoder<?>... componentDecoders) {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100402 this.componentDecoders = componentDecoders;
403 }
404
405 @Override
406 public byte alignment() {
407 return (byte) Arrays.stream(componentDecoders).mapToInt(Decoder::alignment).max().orElse(1);
408 }
409
410 @Override
411 public Integer fixedSize() {
412 int position = 0;
413 for (var componentDecoder : componentDecoders) {
414 var fixedComponentSize = componentDecoder.fixedSize();
415 if (fixedComponentSize == null) {
416 return null;
417 }
418
419 position = align(position, componentDecoder.alignment());
420 position += fixedComponentSize;
421 }
422
423 if (position == 0) {
424 return 1;
425 }
426
427 return align(position, alignment());
428 }
429
430 @Override
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100431 public Object[] decode(ByteBuffer byteSlice) {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100432 int framingOffsetSize = byteCount(byteSlice.limit());
433
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100434 var objects = new Object[componentDecoders.length];
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100435
436 int position = 0;
437 int framingOffsetIndex = 0;
438 int componentIndex = 0;
439 for (var componentDecoder : componentDecoders) {
440 position = align(position, componentDecoder.alignment());
441
442 var fixedComponentSize = componentDecoder.fixedSize();
443 if (fixedComponentSize != null) {
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100444 objects[componentIndex] =
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100445 componentDecoder.decode(byteSlice.slice(position, fixedComponentSize));
446 position += fixedComponentSize;
447 } else {
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100448 if (componentIndex == componentDecoders.length - 1) {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100449 // The last component never has a framing offset.
450 int endPosition = byteSlice.limit() - framingOffsetIndex * framingOffsetSize;
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100451 objects[componentIndex] =
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100452 componentDecoder.decode(byteSlice.slice(position, endPosition - position));
453 position = endPosition;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100454 } else {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100455 int framingOffset =
456 getIntN(
457 byteSlice.slice(
458 byteSlice.limit() - (1 + framingOffsetIndex) * framingOffsetSize,
459 framingOffsetSize));
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100460 objects[componentIndex] =
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100461 componentDecoder.decode(byteSlice.slice(position, framingOffset - position));
462 position = framingOffset;
463 ++framingOffsetIndex;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100464 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100465 }
466
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100467 ++componentIndex;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100468 }
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100469
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100470 return objects;
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100471 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100472 }
473
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +0100474 private static class VariantDecoder extends Decoder<Variant> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100475
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100476 @Override
477 public byte alignment() {
478 return 8;
479 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100480
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100481 @Override
482 @Nullable
483 Integer fixedSize() {
484 return null;
485 }
486
487 @Override
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +0100488 public Variant decode(ByteBuffer byteSlice) {
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100489 for (int i = byteSlice.limit() - 1; i >= 0; --i) {
490 if (byteSlice.get(i) != 0) {
491 continue;
492 }
493
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +0100494 var dataBytes = byteSlice.slice(0, i);
495 var signatureBytes = byteSlice.slice(i + 1, byteSlice.limit() - (i + 1));
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100496
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +0100497 Signature signature;
498 try {
499 signature = Signature.parse(signatureBytes);
500 } catch (ParseException e) {
501 throw new IllegalArgumentException(e);
502 }
503
504 return new Variant(signature, signature.decoder().decode(dataBytes));
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100505 }
506
507 throw new IllegalArgumentException("variant signature not found");
508 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100509 }
510
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100511 private static class BooleanDecoder extends Decoder<Boolean> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100512
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100513 @Override
514 public byte alignment() {
515 return 1;
516 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100517
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100518 @Override
519 public Integer fixedSize() {
520 return 1;
521 }
522
523 @Override
524 public Boolean decode(ByteBuffer byteSlice) {
525 return byteSlice.get() != 0;
526 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100527 }
528
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100529 private static class ByteDecoder extends Decoder<Byte> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100530
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100531 @Override
532 public byte alignment() {
533 return 1;
534 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100535
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100536 @Override
537 public Integer fixedSize() {
538 return 1;
539 }
540
541 @Override
542 public Byte decode(ByteBuffer byteSlice) {
543 return byteSlice.get();
544 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100545 }
546
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100547 private static class ShortDecoder extends Decoder<Short> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100548
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100549 @Override
550 public byte alignment() {
551 return 2;
552 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100553
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100554 @Override
555 public Integer fixedSize() {
556 return 2;
557 }
558
559 @Override
560 public Short decode(ByteBuffer byteSlice) {
561 return byteSlice.getShort();
562 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100563 }
564
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100565 private static class IntegerDecoder extends Decoder<Integer> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100566
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100567 @Override
568 public byte alignment() {
569 return 4;
570 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100571
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100572 @Override
573 public Integer fixedSize() {
574 return 4;
575 }
576
577 @Override
578 public Integer decode(ByteBuffer byteSlice) {
579 return byteSlice.getInt();
580 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100581 }
582
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100583 private static class LongDecoder extends Decoder<Long> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100584
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100585 @Override
586 public byte alignment() {
587 return 8;
588 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100589
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100590 @Override
591 public Integer fixedSize() {
592 return 8;
593 }
594
595 @Override
596 public Long decode(ByteBuffer byteSlice) {
597 return byteSlice.getLong();
598 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100599 }
600
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100601 private static class DoubleDecoder extends Decoder<Double> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100602
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100603 @Override
604 public byte alignment() {
605 return 8;
606 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100607
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100608 @Override
609 public Integer fixedSize() {
610 return 8;
611 }
612
613 @Override
614 public Double decode(ByteBuffer byteSlice) {
615 return byteSlice.getDouble();
616 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100617 }
618
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100619 private static class StringDecoder extends Decoder<String> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100620
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100621 private final Charset charset;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100622
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100623 public StringDecoder(Charset charset) {
624 this.charset = charset;
625 }
626
627 @Override
628 public byte alignment() {
629 return 1;
630 }
631
632 @Override
633 @Nullable
634 Integer fixedSize() {
635 return null;
636 }
637
638 @Override
639 public String decode(ByteBuffer byteSlice) {
640 byteSlice.limit(byteSlice.limit() - 1);
641 return charset.decode(byteSlice).toString();
642 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100643 }
644}