blob: fee0407363d56b7f1faf8d7137d1eaada3cd7bfc [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 Benkard6f993f72021-12-27 22:40:14 +010085 return new ByteOrderFixingDecoder(byteOrder);
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010086 }
87
Matthias Andreas Benkard4c32c392021-12-12 21:23:53 +010088 /**
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +010089 * Creates a new {@link Decoder} from an existing one by applying a function to the result.
90 *
91 * @param function the function to apply.
92 * @return a new, decorated {@link Decoder}.
93 * @see java.util.stream.Stream#map
94 */
95 public final <U> Decoder<U> map(Function<T, U> function) {
Matthias Andreas Benkard6f993f72021-12-27 22:40:14 +010096 return new MappingDecoder<>(function);
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +010097 }
98
99 /**
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100100 * Creates a {@link Decoder} for an {@code Array} type.
Matthias Andreas Benkard4c32c392021-12-12 21:23:53 +0100101 *
102 * @param elementDecoder a {@link Decoder} for the elements of the array.
103 * @param <U> the element type.
104 * @return a new {@link Decoder}.
105 */
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100106 public static <U> Decoder<List<U>> ofArray(Decoder<U> elementDecoder) {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100107 return new ArrayDecoder<>(elementDecoder);
108 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100109
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100110 /**
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +0100111 * Creates a {@link Decoder} for an {@code Array} type of element type {@code byte} into a
112 * primitive {@code byte[]} array.
113 *
114 * @return a new {@link Decoder}.
115 */
116 public static Decoder<byte[]> ofByteArray() {
117 return new ByteArrayDecoder();
118 }
119
120 /**
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100121 * Creates a {@link Decoder} for a {@code Maybe} type.
122 *
123 * @param elementDecoder a {@link Decoder} for the contained element.
124 * @param <U> the element type.
125 * @return a new {@link Decoder}.
126 */
127 public static <U> Decoder<Optional<U>> ofMaybe(Decoder<U> elementDecoder) {
128 return new MaybeDecoder<>(elementDecoder);
129 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100130
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100131 /**
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100132 * Creates a {@link Decoder} for a {@code Structure} type, decoding into a {@link Record}.
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100133 *
134 * @param recordType the {@link Record} type that represents the components of the structure.
135 * @param componentDecoders a {@link Decoder} for each component of the structure.
136 * @param <U> the {@link Record} type that represents the components of the structure.
137 * @return a new {@link Decoder}.
138 */
139 public static <U extends Record> Decoder<U> ofStructure(
140 Class<U> recordType, Decoder<?>... componentDecoders) {
141 return new StructureDecoder<>(recordType, componentDecoders);
142 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100143
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100144 /**
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100145 * Creates a {@link Decoder} for a {@code Structure} type, decoding into a {@link List}.
146 *
147 * <p>Prefer {@link #ofStructure(Class, Decoder[])} if possible, which is both more type-safe and
148 * more convenient.
149 *
150 * @param componentDecoders a {@link Decoder} for each component of the structure.
151 * @return a new {@link Decoder}.
152 */
153 public static Decoder<Object[]> ofStructure(Decoder<?>... componentDecoders) {
154 return new TupleDecoder(componentDecoders);
155 }
156
157 /**
Matthias Andreas Benkardb50fcd02021-12-16 20:17:20 +0100158 * Creates a {@link Decoder} for the {@link Variant} type.
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100159 *
Matthias Andreas Benkardb50fcd02021-12-16 20:17:20 +0100160 * <p>The contained {@link Object} can be of one of the following types:
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100161 *
162 * <ul>
163 * <li>{@link Boolean}
164 * <li>{@link Byte}
165 * <li>{@link Short}
166 * <li>{@link Integer}
167 * <li>{@link Long}
168 * <li>{@link String}
169 * <li>{@link Optional} (a GVariant {@code Maybe} type)
170 * <li>{@link List} (a GVariant array)
Matthias Andreas Benkarda66b73d2021-12-18 19:15:52 +0100171 * <li>{@code Object[]} (a GVariant structure)
Matthias Andreas Benkardb50fcd02021-12-16 20:17:20 +0100172 * <li>{@link Variant} (a nested variant)
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100173 * </ul>
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100174 *
175 * @return a new {@link Decoder}.
176 */
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +0100177 public static Decoder<Variant> ofVariant() {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100178 return new VariantDecoder();
179 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100180
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100181 /**
Matthias Andreas Benkardb50fcd02021-12-16 20:17:20 +0100182 * Creates a {@link Decoder} for the {@code boolean} type.
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100183 *
184 * @return a new {@link Decoder}.
185 */
186 public static Decoder<Boolean> ofBoolean() {
187 return new BooleanDecoder();
188 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100189
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100190 /**
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100191 * Creates a {@link Decoder} for the 8-bit {@code byte} type.
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100192 *
193 * <p><strong>Note:</strong> It is often useful to apply {@link #withByteOrder(ByteOrder)} to the
194 * result of this method.
195 *
196 * @return a new {@link Decoder}.
197 */
198 public static Decoder<Byte> ofByte() {
199 return new ByteDecoder();
200 }
201
202 /**
203 * Creates a {@link Decoder} for the 16-bit {@code short} type.
204 *
205 * <p><strong>Note:</strong> It is often useful to apply {@link #withByteOrder(ByteOrder)} to the
206 * result of this method.
207 *
208 * @return a new {@link Decoder}.
209 */
210 public static Decoder<Short> ofShort() {
211 return new ShortDecoder();
212 }
213
214 /**
215 * Creates a {@link Decoder} for the 32-bit {@code int} type.
216 *
217 * <p><strong>Note:</strong> It is often useful to apply {@link #withByteOrder(ByteOrder)} to the
218 * result of this method.
219 *
220 * @return a new {@link Decoder}.
221 */
222 public static Decoder<Integer> ofInt() {
223 return new IntegerDecoder();
224 }
225
226 /**
227 * Creates a {@link Decoder} for the 64-bit {@code long} type.
228 *
229 * <p><strong>Note:</strong> It is often useful to apply {@link #withByteOrder(ByteOrder)} to the
230 * result of this method.
231 *
232 * @return a new {@link Decoder}.
233 */
234 public static Decoder<Long> ofLong() {
235 return new LongDecoder();
236 }
237
238 /**
239 * Creates a {@link Decoder} for the {@code double} type.
240 *
241 * @return a new {@link Decoder}.
242 */
243 public static Decoder<Double> ofDouble() {
244 return new DoubleDecoder();
245 }
246
247 /**
248 * Creates a {@link Decoder} for the {@link String} type.
249 *
250 * <p><strong>Note:</strong> While GVariant does not prescribe any particular encoding, {@link
251 * java.nio.charset.StandardCharsets#UTF_8} is the most common choice.
252 *
Matthias Andreas Benkard3f13b662021-12-18 18:57:37 +0100253 * @param charset the {@link Charset} the string is encoded in.
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100254 * @return a new {@link Decoder}.
255 */
256 public static Decoder<String> ofString(Charset charset) {
257 return new StringDecoder(charset);
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100258 }
259
260 private static int align(int offset, byte alignment) {
261 return offset % alignment == 0 ? offset : offset + alignment - (offset % alignment);
262 }
263
264 private static int getIntN(ByteBuffer byteSlice) {
265 var intBytes = new byte[4];
266 byteSlice.get(intBytes, 0, Math.min(4, byteSlice.limit()));
267 return ByteBuffer.wrap(intBytes).order(LITTLE_ENDIAN).getInt();
268 }
269
270 @SuppressWarnings("java:S3358")
271 private static int byteCount(int n) {
272 return n < (1 << 8) ? 1 : n < (1 << 16) ? 2 : 4;
273 }
274
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100275 private static class ArrayDecoder<U> extends Decoder<List<U>> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100276
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100277 private final Decoder<U> elementDecoder;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100278
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100279 ArrayDecoder(Decoder<U> elementDecoder) {
280 this.elementDecoder = elementDecoder;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100281 }
282
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100283 @Override
284 public byte alignment() {
285 return elementDecoder.alignment();
286 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100287
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100288 @Override
289 @Nullable
290 Integer fixedSize() {
291 return null;
292 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100293
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100294 @Override
295 public List<U> decode(ByteBuffer byteSlice) {
296 List<U> elements;
297
298 var elementSize = elementDecoder.fixedSize();
299 if (elementSize != null) {
300 // A simple C-style array.
301 elements = new ArrayList<>(byteSlice.limit() / elementSize);
302 for (int i = 0; i < byteSlice.limit(); i += elementSize) {
Matthias Andreas Benkard6f993f72021-12-27 22:40:14 +0100303 var element = elementDecoder.decode(slicePreservingOrder(byteSlice, i, elementSize));
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100304 elements.add(element);
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100305 }
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +0100306 } else if (byteSlice.limit() == 0) {
307 // A degenerate zero-length array of variable width.
308 elements = List.of();
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100309 } else {
310 // An array with aligned elements and a vector of framing offsets in the end.
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100311 int framingOffsetSize = byteCount(byteSlice.limit());
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100312 int lastFramingOffset =
313 getIntN(byteSlice.slice(byteSlice.limit() - framingOffsetSize, framingOffsetSize));
314 int elementCount = (byteSlice.limit() - lastFramingOffset) / framingOffsetSize;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100315
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100316 elements = new ArrayList<>(elementCount);
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100317 int position = 0;
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100318 for (int i = 0; i < elementCount; i++) {
319 int framingOffset =
320 getIntN(
321 byteSlice.slice(lastFramingOffset + i * framingOffsetSize, framingOffsetSize));
Matthias Andreas Benkard6f993f72021-12-27 22:40:14 +0100322 elements.add(
323 elementDecoder.decode(
324 slicePreservingOrder(byteSlice, position, framingOffset - position)));
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100325 position = align(framingOffset, alignment());
326 }
327 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100328
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100329 return elements;
330 }
331 }
332
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +0100333 private static class ByteArrayDecoder extends Decoder<byte[]> {
334
335 private static final int ELEMENT_SIZE = 1;
336
337 @Override
338 public byte alignment() {
339 return ELEMENT_SIZE;
340 }
341
342 @Override
343 @Nullable
344 Integer fixedSize() {
345 return null;
346 }
347
348 @Override
349 public byte[] decode(ByteBuffer byteSlice) {
350 // A simple C-style array.
351 byte[] elements = new byte[byteSlice.limit() / ELEMENT_SIZE];
352 byteSlice.get(elements);
353 return elements;
354 }
355 }
356
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100357 private static class MaybeDecoder<U> extends Decoder<Optional<U>> {
358
359 private final Decoder<U> elementDecoder;
360
361 MaybeDecoder(Decoder<U> elementDecoder) {
362 this.elementDecoder = elementDecoder;
363 }
364
365 @Override
366 public byte alignment() {
367 return elementDecoder.alignment();
368 }
369
370 @Override
371 @Nullable
372 Integer fixedSize() {
373 return null;
374 }
375
376 @Override
377 public Optional<U> decode(ByteBuffer byteSlice) {
378 if (!byteSlice.hasRemaining()) {
379 return Optional.empty();
380 } else {
381 if (!elementDecoder.hasFixedSize()) {
382 // Remove trailing zero byte.
383 byteSlice.limit(byteSlice.limit() - 1);
384 }
385
386 return Optional.of(elementDecoder.decode(byteSlice));
387 }
388 }
389 }
390
391 private static class StructureDecoder<U extends Record> extends Decoder<U> {
392
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100393 private final Class<U> recordType;
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100394 private final TupleDecoder tupleDecoder;
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100395
396 StructureDecoder(Class<U> recordType, Decoder<?>... componentDecoders) {
397 var recordComponents = recordType.getRecordComponents();
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100398 if (componentDecoders.length != recordComponents.length) {
399 throw new IllegalArgumentException(
400 "number of decoders (%d) does not match number of structure components (%d)"
401 .formatted(componentDecoders.length, recordComponents.length));
402 }
403
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100404 this.recordType = recordType;
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100405 this.tupleDecoder = new TupleDecoder(componentDecoders);
406 }
407
408 @Override
409 public byte alignment() {
410 return tupleDecoder.alignment();
411 }
412
413 @Override
414 public Integer fixedSize() {
415 return tupleDecoder.fixedSize();
416 }
417
418 @Override
419 public U decode(ByteBuffer byteSlice) {
420 Object[] recordConstructorArguments = tupleDecoder.decode(byteSlice);
421
422 try {
423 var recordComponentTypes =
424 Arrays.stream(recordType.getRecordComponents())
425 .map(RecordComponent::getType)
426 .toArray(Class<?>[]::new);
427 var recordConstructor = recordType.getDeclaredConstructor(recordComponentTypes);
428 return recordConstructor.newInstance(recordConstructorArguments);
429 } catch (NoSuchMethodException
430 | InstantiationException
431 | IllegalAccessException
432 | InvocationTargetException e) {
433 throw new IllegalStateException(e);
434 }
435 }
436 }
437
438 private static class TupleDecoder extends Decoder<Object[]> {
439
440 private final Decoder<?>[] componentDecoders;
441
442 TupleDecoder(Decoder<?>... componentDecoders) {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100443 this.componentDecoders = componentDecoders;
444 }
445
446 @Override
447 public byte alignment() {
448 return (byte) Arrays.stream(componentDecoders).mapToInt(Decoder::alignment).max().orElse(1);
449 }
450
451 @Override
452 public Integer fixedSize() {
453 int position = 0;
454 for (var componentDecoder : componentDecoders) {
455 var fixedComponentSize = componentDecoder.fixedSize();
456 if (fixedComponentSize == null) {
457 return null;
458 }
459
460 position = align(position, componentDecoder.alignment());
461 position += fixedComponentSize;
462 }
463
464 if (position == 0) {
465 return 1;
466 }
467
468 return align(position, alignment());
469 }
470
471 @Override
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100472 public Object[] decode(ByteBuffer byteSlice) {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100473 int framingOffsetSize = byteCount(byteSlice.limit());
474
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100475 var objects = new Object[componentDecoders.length];
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100476
477 int position = 0;
478 int framingOffsetIndex = 0;
479 int componentIndex = 0;
480 for (var componentDecoder : componentDecoders) {
481 position = align(position, componentDecoder.alignment());
482
483 var fixedComponentSize = componentDecoder.fixedSize();
484 if (fixedComponentSize != null) {
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100485 objects[componentIndex] =
Matthias Andreas Benkard6f993f72021-12-27 22:40:14 +0100486 componentDecoder.decode(
487 slicePreservingOrder(byteSlice, position, fixedComponentSize));
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100488 position += fixedComponentSize;
489 } else {
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100490 if (componentIndex == componentDecoders.length - 1) {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100491 // The last component never has a framing offset.
492 int endPosition = byteSlice.limit() - framingOffsetIndex * framingOffsetSize;
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100493 objects[componentIndex] =
Matthias Andreas Benkard6f993f72021-12-27 22:40:14 +0100494 componentDecoder.decode(
495 slicePreservingOrder(byteSlice, position, endPosition - position));
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100496 position = endPosition;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100497 } else {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100498 int framingOffset =
499 getIntN(
500 byteSlice.slice(
501 byteSlice.limit() - (1 + framingOffsetIndex) * framingOffsetSize,
502 framingOffsetSize));
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100503 objects[componentIndex] =
Matthias Andreas Benkard6f993f72021-12-27 22:40:14 +0100504 componentDecoder.decode(
505 slicePreservingOrder(byteSlice, position, framingOffset - position));
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100506 position = framingOffset;
507 ++framingOffsetIndex;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100508 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100509 }
510
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100511 ++componentIndex;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100512 }
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100513
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100514 return objects;
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100515 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100516 }
517
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +0100518 private static class VariantDecoder extends Decoder<Variant> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100519
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100520 @Override
521 public byte alignment() {
522 return 8;
523 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100524
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100525 @Override
526 @Nullable
527 Integer fixedSize() {
528 return null;
529 }
530
531 @Override
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +0100532 public Variant decode(ByteBuffer byteSlice) {
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100533 for (int i = byteSlice.limit() - 1; i >= 0; --i) {
534 if (byteSlice.get(i) != 0) {
535 continue;
536 }
537
Matthias Andreas Benkard6f993f72021-12-27 22:40:14 +0100538 var dataBytes = slicePreservingOrder(byteSlice, 0, i);
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +0100539 var signatureBytes = byteSlice.slice(i + 1, byteSlice.limit() - (i + 1));
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100540
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +0100541 Signature signature;
542 try {
543 signature = Signature.parse(signatureBytes);
544 } catch (ParseException e) {
545 throw new IllegalArgumentException(e);
546 }
547
548 return new Variant(signature, signature.decoder().decode(dataBytes));
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100549 }
550
551 throw new IllegalArgumentException("variant signature not found");
552 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100553 }
554
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100555 private static class BooleanDecoder extends Decoder<Boolean> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100556
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100557 @Override
558 public byte alignment() {
559 return 1;
560 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100561
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100562 @Override
563 public Integer fixedSize() {
564 return 1;
565 }
566
567 @Override
568 public Boolean decode(ByteBuffer byteSlice) {
569 return byteSlice.get() != 0;
570 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100571 }
572
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100573 private static class ByteDecoder extends Decoder<Byte> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100574
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100575 @Override
576 public byte alignment() {
577 return 1;
578 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100579
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100580 @Override
581 public Integer fixedSize() {
582 return 1;
583 }
584
585 @Override
586 public Byte decode(ByteBuffer byteSlice) {
587 return byteSlice.get();
588 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100589 }
590
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100591 private static class ShortDecoder extends Decoder<Short> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100592
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100593 @Override
594 public byte alignment() {
595 return 2;
596 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100597
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100598 @Override
599 public Integer fixedSize() {
600 return 2;
601 }
602
603 @Override
604 public Short decode(ByteBuffer byteSlice) {
605 return byteSlice.getShort();
606 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100607 }
608
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100609 private static class IntegerDecoder extends Decoder<Integer> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100610
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100611 @Override
612 public byte alignment() {
613 return 4;
614 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100615
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100616 @Override
617 public Integer fixedSize() {
618 return 4;
619 }
620
621 @Override
622 public Integer decode(ByteBuffer byteSlice) {
623 return byteSlice.getInt();
624 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100625 }
626
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100627 private static class LongDecoder extends Decoder<Long> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100628
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100629 @Override
630 public byte alignment() {
631 return 8;
632 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100633
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100634 @Override
635 public Integer fixedSize() {
636 return 8;
637 }
638
639 @Override
640 public Long decode(ByteBuffer byteSlice) {
641 return byteSlice.getLong();
642 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100643 }
644
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100645 private static class DoubleDecoder extends Decoder<Double> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100646
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100647 @Override
648 public byte alignment() {
649 return 8;
650 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100651
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100652 @Override
653 public Integer fixedSize() {
654 return 8;
655 }
656
657 @Override
658 public Double decode(ByteBuffer byteSlice) {
659 return byteSlice.getDouble();
660 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100661 }
662
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100663 private static class StringDecoder extends Decoder<String> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100664
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100665 private final Charset charset;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100666
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100667 public StringDecoder(Charset charset) {
668 this.charset = charset;
669 }
670
671 @Override
672 public byte alignment() {
673 return 1;
674 }
675
676 @Override
677 @Nullable
678 Integer fixedSize() {
679 return null;
680 }
681
682 @Override
683 public String decode(ByteBuffer byteSlice) {
684 byteSlice.limit(byteSlice.limit() - 1);
685 return charset.decode(byteSlice).toString();
686 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100687 }
Matthias Andreas Benkard6f993f72021-12-27 22:40:14 +0100688
689 private class MappingDecoder<U> extends Decoder<U> {
690
691 private final Function<T, U> function;
692
693 public MappingDecoder(Function<T, U> function) {
694 this.function = function;
695 }
696
697 @Override
698 public byte alignment() {
699 return Decoder.this.alignment();
700 }
701
702 @Override
703 public @Nullable Integer fixedSize() {
704 return Decoder.this.fixedSize();
705 }
706
707 @Override
708 public U decode(ByteBuffer byteSlice) {
709 return function.apply(Decoder.this.decode(byteSlice));
710 }
711 }
712
713 private class ByteOrderFixingDecoder extends Decoder<T> {
714
715 private final ByteOrder byteOrder;
716
717 public ByteOrderFixingDecoder(ByteOrder byteOrder) {
718 this.byteOrder = byteOrder;
719 }
720
721 @Override
722 public byte alignment() {
723 return Decoder.this.alignment();
724 }
725
726 @Override
727 public @Nullable Integer fixedSize() {
728 return Decoder.this.fixedSize();
729 }
730
731 @Override
732 public T decode(ByteBuffer byteSlice) {
733 var newByteSlice = byteSlice.duplicate();
734 newByteSlice.order(byteOrder);
735 return Decoder.this.decode(newByteSlice);
736 }
737 }
738
739 private static ByteBuffer slicePreservingOrder(ByteBuffer byteSlice, int index, int length) {
740 return byteSlice.slice(index, length).order(byteSlice.order());
741 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100742}