blob: fc11eabcd04ad6fc739cd1fc293bc137c229c07f [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 Benkard4e8423d2021-12-19 22:56:09 +010015import java.util.function.Function;
Matthias Andreas Benkard25b7f902021-12-17 06:02:11 +010016import org.apiguardian.api.API;
17import org.apiguardian.api.API.Status;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010018import org.jetbrains.annotations.Nullable;
19
20/**
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +010021 * Type class for decodable types.
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010022 *
23 * <p>Use the {@code of*} family of constructor methods to acquire a suitable {@link Decoder} for
24 * the type you wish to decode.
25 *
Matthias Andreas Benkard4c32c392021-12-12 21:23:53 +010026 * <p><strong>Example</strong>
27 *
28 * <p>To parse a GVariant of type {@code "a(si)"}, which is an array of pairs of {@link String} and
29 * {@code int}, you can use the following code:
30 *
31 * <pre>{@code
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +010032 * record ExampleRecord(String s, int i) {}
Matthias Andreas Benkard4c32c392021-12-12 21:23:53 +010033 *
34 * var decoder =
35 * Decoder.ofArray(
36 * Decoder.ofStructure(
37 * ExampleRecord.class,
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +010038 * Decoder.ofString(UTF_8),
39 * Decoder.ofInt().withByteOrder(LITTLE_ENDIAN)));
Matthias Andreas Benkard4c32c392021-12-12 21:23:53 +010040 *
41 * byte[] bytes = ...;
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +010042 * List<ExampleRecord> example = decoder.decode(ByteBuffer.wrap(bytes));
Matthias Andreas Benkard4c32c392021-12-12 21:23:53 +010043 * }</pre>
44 *
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010045 * @param <T> the type that the {@link Decoder} can decode.
46 */
47@SuppressWarnings("java:S1610")
Matthias Andreas Benkard25b7f902021-12-17 06:02:11 +010048@API(status = Status.EXPERIMENTAL)
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +010049public abstract class Decoder<T> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010050
51 private Decoder() {}
52
53 /**
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +010054 * Decodes a {@link ByteBuffer} holding a serialized GVariant into a value of type {@code T}.
55 *
Matthias Andreas Benkard3f13b662021-12-18 18:57:37 +010056 * <p><strong>Note:</strong> Due to the way the GVariant serialization format works, it is
57 * important that the start and end boundaries of the passed byte slice correspond to the actual
58 * start and end of the serialized value. The format does generally not allow for the dynamic
59 * discovery of the end of the data structure.
60 *
61 * @param byteSlice a byte slice holding a serialized GVariant.
62 * @return the deserialized value.
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010063 * @throws java.nio.BufferUnderflowException if the byte buffer is shorter than the requested
64 * data.
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +010065 * @throws IllegalArgumentException if the serialized GVariant is ill-formed
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010066 */
67 public abstract T decode(ByteBuffer byteSlice);
68
69 abstract byte alignment();
70
71 @Nullable
72 abstract Integer fixedSize();
73
74 final boolean hasFixedSize() {
75 return fixedSize() != null;
76 }
77
Matthias Andreas Benkard4c32c392021-12-12 21:23:53 +010078 /**
79 * Switches the input {@link ByteBuffer} to a given {@link ByteOrder} before reading from it.
80 *
81 * @param byteOrder the byte order to use.
82 * @return a new, decorated {@link Decoder}.
83 */
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +010084 public final Decoder<T> withByteOrder(ByteOrder byteOrder) {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010085 var delegate = this;
86
87 return new Decoder<>() {
88 @Override
89 public byte alignment() {
90 return delegate.alignment();
91 }
92
93 @Override
94 public @Nullable Integer fixedSize() {
95 return delegate.fixedSize();
96 }
97
98 @Override
99 public T decode(ByteBuffer byteSlice) {
100 byteSlice.order(byteOrder);
101 return delegate.decode(byteSlice);
102 }
103 };
104 }
105
Matthias Andreas Benkard4c32c392021-12-12 21:23:53 +0100106 /**
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +0100107 * Creates a new {@link Decoder} from an existing one by applying a function to the result.
108 *
109 * @param function the function to apply.
110 * @return a new, decorated {@link Decoder}.
111 * @see java.util.stream.Stream#map
112 */
113 public final <U> Decoder<U> map(Function<T, U> function) {
114 var delegate = this;
115
116 return new Decoder<>() {
117 @Override
118 public byte alignment() {
119 return delegate.alignment();
120 }
121
122 @Override
123 public @Nullable Integer fixedSize() {
124 return delegate.fixedSize();
125 }
126
127 @Override
128 public U decode(ByteBuffer byteSlice) {
129 return function.apply(delegate.decode(byteSlice));
130 }
131 };
132 }
133
134 /**
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100135 * Creates a {@link Decoder} for an {@code Array} type.
Matthias Andreas Benkard4c32c392021-12-12 21:23:53 +0100136 *
137 * @param elementDecoder a {@link Decoder} for the elements of the array.
138 * @param <U> the element type.
139 * @return a new {@link Decoder}.
140 */
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100141 public static <U> Decoder<List<U>> ofArray(Decoder<U> elementDecoder) {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100142 return new ArrayDecoder<>(elementDecoder);
143 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100144
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100145 /**
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +0100146 * Creates a {@link Decoder} for an {@code Array} type of element type {@code byte} into a
147 * primitive {@code byte[]} array.
148 *
149 * @return a new {@link Decoder}.
150 */
151 public static Decoder<byte[]> ofByteArray() {
152 return new ByteArrayDecoder();
153 }
154
155 /**
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100156 * Creates a {@link Decoder} for a {@code Maybe} type.
157 *
158 * @param elementDecoder a {@link Decoder} for the contained element.
159 * @param <U> the element type.
160 * @return a new {@link Decoder}.
161 */
162 public static <U> Decoder<Optional<U>> ofMaybe(Decoder<U> elementDecoder) {
163 return new MaybeDecoder<>(elementDecoder);
164 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100165
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100166 /**
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100167 * Creates a {@link Decoder} for a {@code Structure} type, decoding into a {@link Record}.
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100168 *
169 * @param recordType the {@link Record} type that represents the components of the structure.
170 * @param componentDecoders a {@link Decoder} for each component of the structure.
171 * @param <U> the {@link Record} type that represents the components of the structure.
172 * @return a new {@link Decoder}.
173 */
174 public static <U extends Record> Decoder<U> ofStructure(
175 Class<U> recordType, Decoder<?>... componentDecoders) {
176 return new StructureDecoder<>(recordType, componentDecoders);
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 a {@code Structure} type, decoding into a {@link List}.
181 *
182 * <p>Prefer {@link #ofStructure(Class, Decoder[])} if possible, which is both more type-safe and
183 * more convenient.
184 *
185 * @param componentDecoders a {@link Decoder} for each component of the structure.
186 * @return a new {@link Decoder}.
187 */
188 public static Decoder<Object[]> ofStructure(Decoder<?>... componentDecoders) {
189 return new TupleDecoder(componentDecoders);
190 }
191
192 /**
Matthias Andreas Benkardb50fcd02021-12-16 20:17:20 +0100193 * Creates a {@link Decoder} for the {@link Variant} type.
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100194 *
Matthias Andreas Benkardb50fcd02021-12-16 20:17:20 +0100195 * <p>The contained {@link Object} can be of one of the following types:
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100196 *
197 * <ul>
198 * <li>{@link Boolean}
199 * <li>{@link Byte}
200 * <li>{@link Short}
201 * <li>{@link Integer}
202 * <li>{@link Long}
203 * <li>{@link String}
204 * <li>{@link Optional} (a GVariant {@code Maybe} type)
205 * <li>{@link List} (a GVariant array)
Matthias Andreas Benkarda66b73d2021-12-18 19:15:52 +0100206 * <li>{@code Object[]} (a GVariant structure)
Matthias Andreas Benkardb50fcd02021-12-16 20:17:20 +0100207 * <li>{@link Variant} (a nested variant)
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100208 * </ul>
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100209 *
210 * @return a new {@link Decoder}.
211 */
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +0100212 public static Decoder<Variant> ofVariant() {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100213 return new VariantDecoder();
214 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100215
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100216 /**
Matthias Andreas Benkardb50fcd02021-12-16 20:17:20 +0100217 * Creates a {@link Decoder} for the {@code boolean} type.
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100218 *
219 * @return a new {@link Decoder}.
220 */
221 public static Decoder<Boolean> ofBoolean() {
222 return new BooleanDecoder();
223 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100224
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100225 /**
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100226 * Creates a {@link Decoder} for the 8-bit {@code byte} type.
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100227 *
228 * <p><strong>Note:</strong> It is often useful to apply {@link #withByteOrder(ByteOrder)} to the
229 * result of this method.
230 *
231 * @return a new {@link Decoder}.
232 */
233 public static Decoder<Byte> ofByte() {
234 return new ByteDecoder();
235 }
236
237 /**
238 * Creates a {@link Decoder} for the 16-bit {@code short} type.
239 *
240 * <p><strong>Note:</strong> It is often useful to apply {@link #withByteOrder(ByteOrder)} to the
241 * result of this method.
242 *
243 * @return a new {@link Decoder}.
244 */
245 public static Decoder<Short> ofShort() {
246 return new ShortDecoder();
247 }
248
249 /**
250 * Creates a {@link Decoder} for the 32-bit {@code int} type.
251 *
252 * <p><strong>Note:</strong> It is often useful to apply {@link #withByteOrder(ByteOrder)} to the
253 * result of this method.
254 *
255 * @return a new {@link Decoder}.
256 */
257 public static Decoder<Integer> ofInt() {
258 return new IntegerDecoder();
259 }
260
261 /**
262 * Creates a {@link Decoder} for the 64-bit {@code long} type.
263 *
264 * <p><strong>Note:</strong> It is often useful to apply {@link #withByteOrder(ByteOrder)} to the
265 * result of this method.
266 *
267 * @return a new {@link Decoder}.
268 */
269 public static Decoder<Long> ofLong() {
270 return new LongDecoder();
271 }
272
273 /**
274 * Creates a {@link Decoder} for the {@code double} type.
275 *
276 * @return a new {@link Decoder}.
277 */
278 public static Decoder<Double> ofDouble() {
279 return new DoubleDecoder();
280 }
281
282 /**
283 * Creates a {@link Decoder} for the {@link String} type.
284 *
285 * <p><strong>Note:</strong> While GVariant does not prescribe any particular encoding, {@link
286 * java.nio.charset.StandardCharsets#UTF_8} is the most common choice.
287 *
Matthias Andreas Benkard3f13b662021-12-18 18:57:37 +0100288 * @param charset the {@link Charset} the string is encoded in.
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100289 * @return a new {@link Decoder}.
290 */
291 public static Decoder<String> ofString(Charset charset) {
292 return new StringDecoder(charset);
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100293 }
294
295 private static int align(int offset, byte alignment) {
296 return offset % alignment == 0 ? offset : offset + alignment - (offset % alignment);
297 }
298
299 private static int getIntN(ByteBuffer byteSlice) {
300 var intBytes = new byte[4];
301 byteSlice.get(intBytes, 0, Math.min(4, byteSlice.limit()));
302 return ByteBuffer.wrap(intBytes).order(LITTLE_ENDIAN).getInt();
303 }
304
305 @SuppressWarnings("java:S3358")
306 private static int byteCount(int n) {
307 return n < (1 << 8) ? 1 : n < (1 << 16) ? 2 : 4;
308 }
309
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100310 private static class ArrayDecoder<U> extends Decoder<List<U>> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100311
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100312 private final Decoder<U> elementDecoder;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100313
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100314 ArrayDecoder(Decoder<U> elementDecoder) {
315 this.elementDecoder = elementDecoder;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100316 }
317
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100318 @Override
319 public byte alignment() {
320 return elementDecoder.alignment();
321 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100322
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100323 @Override
324 @Nullable
325 Integer fixedSize() {
326 return null;
327 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100328
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100329 @Override
330 public List<U> decode(ByteBuffer byteSlice) {
331 List<U> elements;
332
333 var elementSize = elementDecoder.fixedSize();
334 if (elementSize != null) {
335 // A simple C-style array.
336 elements = new ArrayList<>(byteSlice.limit() / elementSize);
337 for (int i = 0; i < byteSlice.limit(); i += elementSize) {
338 var element = elementDecoder.decode(byteSlice.slice(i, elementSize));
339 elements.add(element);
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100340 }
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +0100341 } else if (byteSlice.limit() == 0) {
342 // A degenerate zero-length array of variable width.
343 elements = List.of();
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100344 } else {
345 // An array with aligned elements and a vector of framing offsets in the end.
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100346 int framingOffsetSize = byteCount(byteSlice.limit());
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100347 int lastFramingOffset =
348 getIntN(byteSlice.slice(byteSlice.limit() - framingOffsetSize, framingOffsetSize));
349 int elementCount = (byteSlice.limit() - lastFramingOffset) / framingOffsetSize;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100350
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100351 elements = new ArrayList<>(elementCount);
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100352 int position = 0;
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100353 for (int i = 0; i < elementCount; i++) {
354 int framingOffset =
355 getIntN(
356 byteSlice.slice(lastFramingOffset + i * framingOffsetSize, framingOffsetSize));
357 elements.add(elementDecoder.decode(byteSlice.slice(position, framingOffset - position)));
358 position = align(framingOffset, alignment());
359 }
360 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100361
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100362 return elements;
363 }
364 }
365
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +0100366 private static class ByteArrayDecoder extends Decoder<byte[]> {
367
368 private static final int ELEMENT_SIZE = 1;
369
370 @Override
371 public byte alignment() {
372 return ELEMENT_SIZE;
373 }
374
375 @Override
376 @Nullable
377 Integer fixedSize() {
378 return null;
379 }
380
381 @Override
382 public byte[] decode(ByteBuffer byteSlice) {
383 // A simple C-style array.
384 byte[] elements = new byte[byteSlice.limit() / ELEMENT_SIZE];
385 byteSlice.get(elements);
386 return elements;
387 }
388 }
389
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100390 private static class MaybeDecoder<U> extends Decoder<Optional<U>> {
391
392 private final Decoder<U> elementDecoder;
393
394 MaybeDecoder(Decoder<U> elementDecoder) {
395 this.elementDecoder = elementDecoder;
396 }
397
398 @Override
399 public byte alignment() {
400 return elementDecoder.alignment();
401 }
402
403 @Override
404 @Nullable
405 Integer fixedSize() {
406 return null;
407 }
408
409 @Override
410 public Optional<U> decode(ByteBuffer byteSlice) {
411 if (!byteSlice.hasRemaining()) {
412 return Optional.empty();
413 } else {
414 if (!elementDecoder.hasFixedSize()) {
415 // Remove trailing zero byte.
416 byteSlice.limit(byteSlice.limit() - 1);
417 }
418
419 return Optional.of(elementDecoder.decode(byteSlice));
420 }
421 }
422 }
423
424 private static class StructureDecoder<U extends Record> extends Decoder<U> {
425
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100426 private final Class<U> recordType;
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100427 private final TupleDecoder tupleDecoder;
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100428
429 StructureDecoder(Class<U> recordType, Decoder<?>... componentDecoders) {
430 var recordComponents = recordType.getRecordComponents();
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100431 if (componentDecoders.length != recordComponents.length) {
432 throw new IllegalArgumentException(
433 "number of decoders (%d) does not match number of structure components (%d)"
434 .formatted(componentDecoders.length, recordComponents.length));
435 }
436
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100437 this.recordType = recordType;
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100438 this.tupleDecoder = new TupleDecoder(componentDecoders);
439 }
440
441 @Override
442 public byte alignment() {
443 return tupleDecoder.alignment();
444 }
445
446 @Override
447 public Integer fixedSize() {
448 return tupleDecoder.fixedSize();
449 }
450
451 @Override
452 public U decode(ByteBuffer byteSlice) {
453 Object[] recordConstructorArguments = tupleDecoder.decode(byteSlice);
454
455 try {
456 var recordComponentTypes =
457 Arrays.stream(recordType.getRecordComponents())
458 .map(RecordComponent::getType)
459 .toArray(Class<?>[]::new);
460 var recordConstructor = recordType.getDeclaredConstructor(recordComponentTypes);
461 return recordConstructor.newInstance(recordConstructorArguments);
462 } catch (NoSuchMethodException
463 | InstantiationException
464 | IllegalAccessException
465 | InvocationTargetException e) {
466 throw new IllegalStateException(e);
467 }
468 }
469 }
470
471 private static class TupleDecoder extends Decoder<Object[]> {
472
473 private final Decoder<?>[] componentDecoders;
474
475 TupleDecoder(Decoder<?>... componentDecoders) {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100476 this.componentDecoders = componentDecoders;
477 }
478
479 @Override
480 public byte alignment() {
481 return (byte) Arrays.stream(componentDecoders).mapToInt(Decoder::alignment).max().orElse(1);
482 }
483
484 @Override
485 public Integer fixedSize() {
486 int position = 0;
487 for (var componentDecoder : componentDecoders) {
488 var fixedComponentSize = componentDecoder.fixedSize();
489 if (fixedComponentSize == null) {
490 return null;
491 }
492
493 position = align(position, componentDecoder.alignment());
494 position += fixedComponentSize;
495 }
496
497 if (position == 0) {
498 return 1;
499 }
500
501 return align(position, alignment());
502 }
503
504 @Override
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100505 public Object[] decode(ByteBuffer byteSlice) {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100506 int framingOffsetSize = byteCount(byteSlice.limit());
507
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100508 var objects = new Object[componentDecoders.length];
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100509
510 int position = 0;
511 int framingOffsetIndex = 0;
512 int componentIndex = 0;
513 for (var componentDecoder : componentDecoders) {
514 position = align(position, componentDecoder.alignment());
515
516 var fixedComponentSize = componentDecoder.fixedSize();
517 if (fixedComponentSize != null) {
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100518 objects[componentIndex] =
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100519 componentDecoder.decode(byteSlice.slice(position, fixedComponentSize));
520 position += fixedComponentSize;
521 } else {
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100522 if (componentIndex == componentDecoders.length - 1) {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100523 // The last component never has a framing offset.
524 int endPosition = byteSlice.limit() - framingOffsetIndex * framingOffsetSize;
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100525 objects[componentIndex] =
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100526 componentDecoder.decode(byteSlice.slice(position, endPosition - position));
527 position = endPosition;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100528 } else {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100529 int framingOffset =
530 getIntN(
531 byteSlice.slice(
532 byteSlice.limit() - (1 + framingOffsetIndex) * framingOffsetSize,
533 framingOffsetSize));
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100534 objects[componentIndex] =
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100535 componentDecoder.decode(byteSlice.slice(position, framingOffset - position));
536 position = framingOffset;
537 ++framingOffsetIndex;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100538 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100539 }
540
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100541 ++componentIndex;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100542 }
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100543
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100544 return objects;
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100545 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100546 }
547
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +0100548 private static class VariantDecoder extends Decoder<Variant> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100549
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100550 @Override
551 public byte alignment() {
552 return 8;
553 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100554
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100555 @Override
556 @Nullable
557 Integer fixedSize() {
558 return null;
559 }
560
561 @Override
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +0100562 public Variant decode(ByteBuffer byteSlice) {
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100563 for (int i = byteSlice.limit() - 1; i >= 0; --i) {
564 if (byteSlice.get(i) != 0) {
565 continue;
566 }
567
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +0100568 var dataBytes = byteSlice.slice(0, i);
569 var signatureBytes = byteSlice.slice(i + 1, byteSlice.limit() - (i + 1));
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100570
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +0100571 Signature signature;
572 try {
573 signature = Signature.parse(signatureBytes);
574 } catch (ParseException e) {
575 throw new IllegalArgumentException(e);
576 }
577
578 return new Variant(signature, signature.decoder().decode(dataBytes));
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100579 }
580
581 throw new IllegalArgumentException("variant signature not found");
582 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100583 }
584
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100585 private static class BooleanDecoder extends Decoder<Boolean> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100586
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100587 @Override
588 public byte alignment() {
589 return 1;
590 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100591
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100592 @Override
593 public Integer fixedSize() {
594 return 1;
595 }
596
597 @Override
598 public Boolean decode(ByteBuffer byteSlice) {
599 return byteSlice.get() != 0;
600 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100601 }
602
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100603 private static class ByteDecoder extends Decoder<Byte> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100604
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100605 @Override
606 public byte alignment() {
607 return 1;
608 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100609
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100610 @Override
611 public Integer fixedSize() {
612 return 1;
613 }
614
615 @Override
616 public Byte decode(ByteBuffer byteSlice) {
617 return byteSlice.get();
618 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100619 }
620
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100621 private static class ShortDecoder extends Decoder<Short> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100622
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100623 @Override
624 public byte alignment() {
625 return 2;
626 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100627
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100628 @Override
629 public Integer fixedSize() {
630 return 2;
631 }
632
633 @Override
634 public Short decode(ByteBuffer byteSlice) {
635 return byteSlice.getShort();
636 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100637 }
638
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100639 private static class IntegerDecoder extends Decoder<Integer> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100640
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100641 @Override
642 public byte alignment() {
643 return 4;
644 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100645
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100646 @Override
647 public Integer fixedSize() {
648 return 4;
649 }
650
651 @Override
652 public Integer decode(ByteBuffer byteSlice) {
653 return byteSlice.getInt();
654 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100655 }
656
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100657 private static class LongDecoder extends Decoder<Long> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100658
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100659 @Override
660 public byte alignment() {
661 return 8;
662 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100663
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100664 @Override
665 public Integer fixedSize() {
666 return 8;
667 }
668
669 @Override
670 public Long decode(ByteBuffer byteSlice) {
671 return byteSlice.getLong();
672 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100673 }
674
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100675 private static class DoubleDecoder extends Decoder<Double> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100676
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100677 @Override
678 public byte alignment() {
679 return 8;
680 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100681
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100682 @Override
683 public Integer fixedSize() {
684 return 8;
685 }
686
687 @Override
688 public Double decode(ByteBuffer byteSlice) {
689 return byteSlice.getDouble();
690 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100691 }
692
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100693 private static class StringDecoder extends Decoder<String> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100694
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100695 private final Charset charset;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100696
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100697 public StringDecoder(Charset charset) {
698 this.charset = charset;
699 }
700
701 @Override
702 public byte alignment() {
703 return 1;
704 }
705
706 @Override
707 @Nullable
708 Integer fixedSize() {
709 return null;
710 }
711
712 @Override
713 public String decode(ByteBuffer byteSlice) {
714 byteSlice.limit(byteSlice.limit() - 1);
715 return charset.decode(byteSlice).toString();
716 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100717 }
718}