blob: 96e1332be393d57a0b44e40ef2275d69add319ba [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 Benkardcd924f62021-12-28 00:46:06 +010011import java.util.AbstractMap.SimpleImmutableEntry;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010012import java.util.ArrayList;
13import java.util.Arrays;
14import java.util.List;
Matthias Andreas Benkardcd924f62021-12-28 00:46:06 +010015import java.util.Map;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010016import java.util.Optional;
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +010017import java.util.function.Function;
Matthias Andreas Benkard25b7f902021-12-17 06:02:11 +010018import org.apiguardian.api.API;
19import org.apiguardian.api.API.Status;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010020import org.jetbrains.annotations.Nullable;
21
22/**
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +010023 * Type class for decodable types.
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010024 *
25 * <p>Use the {@code of*} family of constructor methods to acquire a suitable {@link Decoder} for
26 * the type you wish to decode.
27 *
Matthias Andreas Benkard4c32c392021-12-12 21:23:53 +010028 * <p><strong>Example</strong>
29 *
30 * <p>To parse a GVariant of type {@code "a(si)"}, which is an array of pairs of {@link String} and
31 * {@code int}, you can use the following code:
32 *
33 * <pre>{@code
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +010034 * record ExampleRecord(String s, int i) {}
Matthias Andreas Benkard4c32c392021-12-12 21:23:53 +010035 *
36 * var decoder =
37 * Decoder.ofArray(
38 * Decoder.ofStructure(
39 * ExampleRecord.class,
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +010040 * Decoder.ofString(UTF_8),
41 * Decoder.ofInt().withByteOrder(LITTLE_ENDIAN)));
Matthias Andreas Benkard4c32c392021-12-12 21:23:53 +010042 *
43 * byte[] bytes = ...;
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +010044 * List<ExampleRecord> example = decoder.decode(ByteBuffer.wrap(bytes));
Matthias Andreas Benkard4c32c392021-12-12 21:23:53 +010045 * }</pre>
46 *
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010047 * @param <T> the type that the {@link Decoder} can decode.
48 */
49@SuppressWarnings("java:S1610")
Matthias Andreas Benkard25b7f902021-12-17 06:02:11 +010050@API(status = Status.EXPERIMENTAL)
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +010051public abstract class Decoder<T> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010052
53 private Decoder() {}
54
55 /**
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +010056 * Decodes a {@link ByteBuffer} holding a serialized GVariant into a value of type {@code T}.
57 *
Matthias Andreas Benkard3f13b662021-12-18 18:57:37 +010058 * <p><strong>Note:</strong> Due to the way the GVariant serialization format works, it is
59 * important that the start and end boundaries of the passed byte slice correspond to the actual
60 * start and end of the serialized value. The format does generally not allow for the dynamic
61 * discovery of the end of the data structure.
62 *
63 * @param byteSlice a byte slice holding a serialized GVariant.
64 * @return the deserialized value.
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010065 * @throws java.nio.BufferUnderflowException if the byte buffer is shorter than the requested
66 * data.
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +010067 * @throws IllegalArgumentException if the serialized GVariant is ill-formed
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010068 */
69 public abstract T decode(ByteBuffer byteSlice);
70
71 abstract byte alignment();
72
73 @Nullable
74 abstract Integer fixedSize();
75
76 final boolean hasFixedSize() {
77 return fixedSize() != null;
78 }
79
Matthias Andreas Benkard4c32c392021-12-12 21:23:53 +010080 /**
81 * Switches the input {@link ByteBuffer} to a given {@link ByteOrder} before reading from it.
82 *
83 * @param byteOrder the byte order to use.
84 * @return a new, decorated {@link Decoder}.
85 */
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +010086 public final Decoder<T> withByteOrder(ByteOrder byteOrder) {
Matthias Andreas Benkard6f993f72021-12-27 22:40:14 +010087 return new ByteOrderFixingDecoder(byteOrder);
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +010088 }
89
Matthias Andreas Benkard4c32c392021-12-12 21:23:53 +010090 /**
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +010091 * Creates a new {@link Decoder} from an existing one by applying a function to the result.
92 *
93 * @param function the function to apply.
94 * @return a new, decorated {@link Decoder}.
95 * @see java.util.stream.Stream#map
96 */
97 public final <U> Decoder<U> map(Function<T, U> function) {
Matthias Andreas Benkard6f993f72021-12-27 22:40:14 +010098 return new MappingDecoder<>(function);
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +010099 }
100
101 /**
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100102 * Creates a {@link Decoder} for an {@code Array} type.
Matthias Andreas Benkard4c32c392021-12-12 21:23:53 +0100103 *
104 * @param elementDecoder a {@link Decoder} for the elements of the array.
105 * @param <U> the element type.
106 * @return a new {@link Decoder}.
107 */
Matthias Andreas Benkard35f7a202021-12-14 19:29:26 +0100108 public static <U> Decoder<List<U>> ofArray(Decoder<U> elementDecoder) {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100109 return new ArrayDecoder<>(elementDecoder);
110 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100111
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100112 /**
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +0100113 * Creates a {@link Decoder} for an {@code Array} type of element type {@code byte} into a
114 * primitive {@code byte[]} array.
115 *
116 * @return a new {@link Decoder}.
117 */
118 public static Decoder<byte[]> ofByteArray() {
119 return new ByteArrayDecoder();
120 }
121
122 /**
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100123 * Creates a {@link Decoder} for a {@code Maybe} type.
124 *
125 * @param elementDecoder a {@link Decoder} for the contained element.
126 * @param <U> the element type.
127 * @return a new {@link Decoder}.
128 */
129 public static <U> Decoder<Optional<U>> ofMaybe(Decoder<U> elementDecoder) {
130 return new MaybeDecoder<>(elementDecoder);
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 Record}.
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100135 *
136 * @param recordType the {@link Record} type that represents the components of the structure.
137 * @param componentDecoders a {@link Decoder} for each component of the structure.
138 * @param <U> the {@link Record} type that represents the components of the structure.
139 * @return a new {@link Decoder}.
140 */
141 public static <U extends Record> Decoder<U> ofStructure(
142 Class<U> recordType, Decoder<?>... componentDecoders) {
143 return new StructureDecoder<>(recordType, componentDecoders);
144 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100145
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100146 /**
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100147 * Creates a {@link Decoder} for a {@code Structure} type, decoding into a {@link List}.
148 *
149 * <p>Prefer {@link #ofStructure(Class, Decoder[])} if possible, which is both more type-safe and
150 * more convenient.
151 *
152 * @param componentDecoders a {@link Decoder} for each component of the structure.
153 * @return a new {@link Decoder}.
154 */
155 public static Decoder<Object[]> ofStructure(Decoder<?>... componentDecoders) {
156 return new TupleDecoder(componentDecoders);
157 }
158
159 /**
Matthias Andreas Benkardcd924f62021-12-28 00:46:06 +0100160 * Creates a {@link Decoder} for a {@code Dictionary Entry} type, decoding into a {@link
161 * Map.Entry}.
162 *
163 * @param keyDecoder a {@link Decoder} for the key component of the dictionary entry.
164 * @param valueDecoder a {@link Decoder} for the value component of the dictionary entry.
165 * @return a new {@link Decoder}.
166 */
167 public static <K, V> Decoder<Map.Entry<K, V>> ofDictionaryEntry(
168 Decoder<K> keyDecoder, Decoder<V> valueDecoder) {
169 return new DictionaryEntryDecoder<>(keyDecoder, valueDecoder);
170 }
171
172 /**
Matthias Andreas Benkardb50fcd02021-12-16 20:17:20 +0100173 * Creates a {@link Decoder} for the {@link Variant} type.
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100174 *
Matthias Andreas Benkardb50fcd02021-12-16 20:17:20 +0100175 * <p>The contained {@link Object} can be of one of the following types:
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100176 *
177 * <ul>
178 * <li>{@link Boolean}
179 * <li>{@link Byte}
180 * <li>{@link Short}
181 * <li>{@link Integer}
182 * <li>{@link Long}
183 * <li>{@link String}
184 * <li>{@link Optional} (a GVariant {@code Maybe} type)
185 * <li>{@link List} (a GVariant array)
Matthias Andreas Benkarda66b73d2021-12-18 19:15:52 +0100186 * <li>{@code Object[]} (a GVariant structure)
Matthias Andreas Benkardcd924f62021-12-28 00:46:06 +0100187 * <li>{@link java.util.Map.Entry} (a dictionary entry)
Matthias Andreas Benkardb50fcd02021-12-16 20:17:20 +0100188 * <li>{@link Variant} (a nested variant)
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100189 * </ul>
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100190 *
191 * @return a new {@link Decoder}.
192 */
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +0100193 public static Decoder<Variant> ofVariant() {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100194 return new VariantDecoder();
195 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100196
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100197 /**
Matthias Andreas Benkardb50fcd02021-12-16 20:17:20 +0100198 * Creates a {@link Decoder} for the {@code boolean} type.
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100199 *
200 * @return a new {@link Decoder}.
201 */
202 public static Decoder<Boolean> ofBoolean() {
203 return new BooleanDecoder();
204 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100205
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100206 /**
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100207 * Creates a {@link Decoder} for the 8-bit {@code byte} type.
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100208 *
209 * <p><strong>Note:</strong> It is often useful to apply {@link #withByteOrder(ByteOrder)} to the
210 * result of this method.
211 *
212 * @return a new {@link Decoder}.
213 */
214 public static Decoder<Byte> ofByte() {
215 return new ByteDecoder();
216 }
217
218 /**
219 * Creates a {@link Decoder} for the 16-bit {@code short} type.
220 *
221 * <p><strong>Note:</strong> It is often useful to apply {@link #withByteOrder(ByteOrder)} to the
222 * result of this method.
223 *
224 * @return a new {@link Decoder}.
225 */
226 public static Decoder<Short> ofShort() {
227 return new ShortDecoder();
228 }
229
230 /**
231 * Creates a {@link Decoder} for the 32-bit {@code int} type.
232 *
233 * <p><strong>Note:</strong> It is often useful to apply {@link #withByteOrder(ByteOrder)} to the
234 * result of this method.
235 *
236 * @return a new {@link Decoder}.
237 */
238 public static Decoder<Integer> ofInt() {
239 return new IntegerDecoder();
240 }
241
242 /**
243 * Creates a {@link Decoder} for the 64-bit {@code long} type.
244 *
245 * <p><strong>Note:</strong> It is often useful to apply {@link #withByteOrder(ByteOrder)} to the
246 * result of this method.
247 *
248 * @return a new {@link Decoder}.
249 */
250 public static Decoder<Long> ofLong() {
251 return new LongDecoder();
252 }
253
254 /**
255 * Creates a {@link Decoder} for the {@code double} type.
256 *
257 * @return a new {@link Decoder}.
258 */
259 public static Decoder<Double> ofDouble() {
260 return new DoubleDecoder();
261 }
262
263 /**
264 * Creates a {@link Decoder} for the {@link String} type.
265 *
266 * <p><strong>Note:</strong> While GVariant does not prescribe any particular encoding, {@link
267 * java.nio.charset.StandardCharsets#UTF_8} is the most common choice.
268 *
Matthias Andreas Benkard3f13b662021-12-18 18:57:37 +0100269 * @param charset the {@link Charset} the string is encoded in.
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100270 * @return a new {@link Decoder}.
271 */
272 public static Decoder<String> ofString(Charset charset) {
273 return new StringDecoder(charset);
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100274 }
275
276 private static int align(int offset, byte alignment) {
277 return offset % alignment == 0 ? offset : offset + alignment - (offset % alignment);
278 }
279
280 private static int getIntN(ByteBuffer byteSlice) {
281 var intBytes = new byte[4];
282 byteSlice.get(intBytes, 0, Math.min(4, byteSlice.limit()));
283 return ByteBuffer.wrap(intBytes).order(LITTLE_ENDIAN).getInt();
284 }
285
286 @SuppressWarnings("java:S3358")
287 private static int byteCount(int n) {
288 return n < (1 << 8) ? 1 : n < (1 << 16) ? 2 : 4;
289 }
290
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100291 private static class ArrayDecoder<U> extends Decoder<List<U>> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100292
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100293 private final Decoder<U> elementDecoder;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100294
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100295 ArrayDecoder(Decoder<U> elementDecoder) {
296 this.elementDecoder = elementDecoder;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100297 }
298
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100299 @Override
300 public byte alignment() {
301 return elementDecoder.alignment();
302 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100303
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100304 @Override
305 @Nullable
306 Integer fixedSize() {
307 return null;
308 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100309
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100310 @Override
311 public List<U> decode(ByteBuffer byteSlice) {
312 List<U> elements;
313
314 var elementSize = elementDecoder.fixedSize();
315 if (elementSize != null) {
316 // A simple C-style array.
317 elements = new ArrayList<>(byteSlice.limit() / elementSize);
318 for (int i = 0; i < byteSlice.limit(); i += elementSize) {
Matthias Andreas Benkard6f993f72021-12-27 22:40:14 +0100319 var element = elementDecoder.decode(slicePreservingOrder(byteSlice, i, elementSize));
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100320 elements.add(element);
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100321 }
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +0100322 } else if (byteSlice.limit() == 0) {
323 // A degenerate zero-length array of variable width.
324 elements = List.of();
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100325 } else {
326 // An array with aligned elements and a vector of framing offsets in the end.
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100327 int framingOffsetSize = byteCount(byteSlice.limit());
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100328 int lastFramingOffset =
329 getIntN(byteSlice.slice(byteSlice.limit() - framingOffsetSize, framingOffsetSize));
330 int elementCount = (byteSlice.limit() - lastFramingOffset) / framingOffsetSize;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100331
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100332 elements = new ArrayList<>(elementCount);
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100333 int position = 0;
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100334 for (int i = 0; i < elementCount; i++) {
335 int framingOffset =
336 getIntN(
337 byteSlice.slice(lastFramingOffset + i * framingOffsetSize, framingOffsetSize));
Matthias Andreas Benkard6f993f72021-12-27 22:40:14 +0100338 elements.add(
339 elementDecoder.decode(
340 slicePreservingOrder(byteSlice, position, framingOffset - position)));
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100341 position = align(framingOffset, alignment());
342 }
343 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100344
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100345 return elements;
346 }
347 }
348
Matthias Andreas Benkard4e8423d2021-12-19 22:56:09 +0100349 private static class ByteArrayDecoder extends Decoder<byte[]> {
350
351 private static final int ELEMENT_SIZE = 1;
352
353 @Override
354 public byte alignment() {
355 return ELEMENT_SIZE;
356 }
357
358 @Override
359 @Nullable
360 Integer fixedSize() {
361 return null;
362 }
363
364 @Override
365 public byte[] decode(ByteBuffer byteSlice) {
366 // A simple C-style array.
367 byte[] elements = new byte[byteSlice.limit() / ELEMENT_SIZE];
368 byteSlice.get(elements);
369 return elements;
370 }
371 }
372
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100373 private static class MaybeDecoder<U> extends Decoder<Optional<U>> {
374
375 private final Decoder<U> elementDecoder;
376
377 MaybeDecoder(Decoder<U> elementDecoder) {
378 this.elementDecoder = elementDecoder;
379 }
380
381 @Override
382 public byte alignment() {
383 return elementDecoder.alignment();
384 }
385
386 @Override
387 @Nullable
388 Integer fixedSize() {
389 return null;
390 }
391
392 @Override
393 public Optional<U> decode(ByteBuffer byteSlice) {
394 if (!byteSlice.hasRemaining()) {
395 return Optional.empty();
396 } else {
397 if (!elementDecoder.hasFixedSize()) {
398 // Remove trailing zero byte.
399 byteSlice.limit(byteSlice.limit() - 1);
400 }
401
402 return Optional.of(elementDecoder.decode(byteSlice));
403 }
404 }
405 }
406
407 private static class StructureDecoder<U extends Record> extends Decoder<U> {
408
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100409 private final Class<U> recordType;
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100410 private final TupleDecoder tupleDecoder;
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100411
412 StructureDecoder(Class<U> recordType, Decoder<?>... componentDecoders) {
413 var recordComponents = recordType.getRecordComponents();
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100414 if (componentDecoders.length != recordComponents.length) {
415 throw new IllegalArgumentException(
416 "number of decoders (%d) does not match number of structure components (%d)"
417 .formatted(componentDecoders.length, recordComponents.length));
418 }
419
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100420 this.recordType = recordType;
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100421 this.tupleDecoder = new TupleDecoder(componentDecoders);
422 }
423
424 @Override
425 public byte alignment() {
426 return tupleDecoder.alignment();
427 }
428
429 @Override
430 public Integer fixedSize() {
431 return tupleDecoder.fixedSize();
432 }
433
434 @Override
435 public U decode(ByteBuffer byteSlice) {
436 Object[] recordConstructorArguments = tupleDecoder.decode(byteSlice);
437
438 try {
439 var recordComponentTypes =
440 Arrays.stream(recordType.getRecordComponents())
441 .map(RecordComponent::getType)
442 .toArray(Class<?>[]::new);
443 var recordConstructor = recordType.getDeclaredConstructor(recordComponentTypes);
444 return recordConstructor.newInstance(recordConstructorArguments);
445 } catch (NoSuchMethodException
446 | InstantiationException
447 | IllegalAccessException
448 | InvocationTargetException e) {
449 throw new IllegalStateException(e);
450 }
451 }
452 }
453
454 private static class TupleDecoder extends Decoder<Object[]> {
455
456 private final Decoder<?>[] componentDecoders;
457
458 TupleDecoder(Decoder<?>... componentDecoders) {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100459 this.componentDecoders = componentDecoders;
460 }
461
462 @Override
463 public byte alignment() {
464 return (byte) Arrays.stream(componentDecoders).mapToInt(Decoder::alignment).max().orElse(1);
465 }
466
467 @Override
468 public Integer fixedSize() {
469 int position = 0;
470 for (var componentDecoder : componentDecoders) {
471 var fixedComponentSize = componentDecoder.fixedSize();
472 if (fixedComponentSize == null) {
473 return null;
474 }
475
476 position = align(position, componentDecoder.alignment());
477 position += fixedComponentSize;
478 }
479
480 if (position == 0) {
481 return 1;
482 }
483
484 return align(position, alignment());
485 }
486
487 @Override
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100488 public Object[] decode(ByteBuffer byteSlice) {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100489 int framingOffsetSize = byteCount(byteSlice.limit());
490
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100491 var objects = new Object[componentDecoders.length];
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100492
493 int position = 0;
494 int framingOffsetIndex = 0;
495 int componentIndex = 0;
496 for (var componentDecoder : componentDecoders) {
497 position = align(position, componentDecoder.alignment());
498
499 var fixedComponentSize = componentDecoder.fixedSize();
500 if (fixedComponentSize != null) {
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100501 objects[componentIndex] =
Matthias Andreas Benkard6f993f72021-12-27 22:40:14 +0100502 componentDecoder.decode(
503 slicePreservingOrder(byteSlice, position, fixedComponentSize));
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100504 position += fixedComponentSize;
505 } else {
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100506 if (componentIndex == componentDecoders.length - 1) {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100507 // The last component never has a framing offset.
508 int endPosition = byteSlice.limit() - framingOffsetIndex * framingOffsetSize;
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100509 objects[componentIndex] =
Matthias Andreas Benkard6f993f72021-12-27 22:40:14 +0100510 componentDecoder.decode(
511 slicePreservingOrder(byteSlice, position, endPosition - position));
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100512 position = endPosition;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100513 } else {
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100514 int framingOffset =
515 getIntN(
516 byteSlice.slice(
517 byteSlice.limit() - (1 + framingOffsetIndex) * framingOffsetSize,
518 framingOffsetSize));
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100519 objects[componentIndex] =
Matthias Andreas Benkard6f993f72021-12-27 22:40:14 +0100520 componentDecoder.decode(
521 slicePreservingOrder(byteSlice, position, framingOffset - position));
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100522 position = framingOffset;
523 ++framingOffsetIndex;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100524 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100525 }
526
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100527 ++componentIndex;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100528 }
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100529
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100530 return objects;
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100531 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100532 }
533
Matthias Andreas Benkardcd924f62021-12-28 00:46:06 +0100534 private static class DictionaryEntryDecoder<K, V> extends Decoder<Map.Entry<K, V>> {
535
536 private final TupleDecoder tupleDecoder;
537
538 DictionaryEntryDecoder(Decoder<K> keyDecoder, Decoder<V> valueDecoder) {
539 this.tupleDecoder = new TupleDecoder(keyDecoder, valueDecoder);
540 }
541
542 @Override
543 public byte alignment() {
544 return tupleDecoder.alignment();
545 }
546
547 @Override
548 public Integer fixedSize() {
549 return tupleDecoder.fixedSize();
550 }
551
552 @Override
553 @SuppressWarnings("unchecked")
554 public Map.Entry<K, V> decode(ByteBuffer byteSlice) {
555 Object[] components = tupleDecoder.decode(byteSlice);
556 return new SimpleImmutableEntry<>((K) components[0], (V) components[1]);
557 }
558 }
559
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +0100560 private static class VariantDecoder extends Decoder<Variant> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100561
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100562 @Override
563 public byte alignment() {
564 return 8;
565 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100566
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100567 @Override
568 @Nullable
569 Integer fixedSize() {
570 return null;
571 }
572
573 @Override
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +0100574 public Variant decode(ByteBuffer byteSlice) {
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100575 for (int i = byteSlice.limit() - 1; i >= 0; --i) {
576 if (byteSlice.get(i) != 0) {
577 continue;
578 }
579
Matthias Andreas Benkard6f993f72021-12-27 22:40:14 +0100580 var dataBytes = slicePreservingOrder(byteSlice, 0, i);
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +0100581 var signatureBytes = byteSlice.slice(i + 1, byteSlice.limit() - (i + 1));
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100582
Matthias Andreas Benkard31c61e72021-12-16 20:06:39 +0100583 Signature signature;
584 try {
585 signature = Signature.parse(signatureBytes);
586 } catch (ParseException e) {
587 throw new IllegalArgumentException(e);
588 }
589
590 return new Variant(signature, signature.decoder().decode(dataBytes));
Matthias Andreas Benkard55c34812021-12-14 21:51:10 +0100591 }
592
593 throw new IllegalArgumentException("variant signature not found");
594 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100595 }
596
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100597 private static class BooleanDecoder extends Decoder<Boolean> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100598
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100599 @Override
600 public byte alignment() {
601 return 1;
602 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100603
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100604 @Override
605 public Integer fixedSize() {
606 return 1;
607 }
608
609 @Override
610 public Boolean decode(ByteBuffer byteSlice) {
611 return byteSlice.get() != 0;
612 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100613 }
614
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100615 private static class ByteDecoder extends Decoder<Byte> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100616
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100617 @Override
618 public byte alignment() {
619 return 1;
620 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100621
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100622 @Override
623 public Integer fixedSize() {
624 return 1;
625 }
626
627 @Override
628 public Byte decode(ByteBuffer byteSlice) {
629 return byteSlice.get();
630 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100631 }
632
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100633 private static class ShortDecoder extends Decoder<Short> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100634
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100635 @Override
636 public byte alignment() {
637 return 2;
638 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100639
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100640 @Override
641 public Integer fixedSize() {
642 return 2;
643 }
644
645 @Override
646 public Short decode(ByteBuffer byteSlice) {
647 return byteSlice.getShort();
648 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100649 }
650
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100651 private static class IntegerDecoder extends Decoder<Integer> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100652
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100653 @Override
654 public byte alignment() {
655 return 4;
656 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100657
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100658 @Override
659 public Integer fixedSize() {
660 return 4;
661 }
662
663 @Override
664 public Integer decode(ByteBuffer byteSlice) {
665 return byteSlice.getInt();
666 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100667 }
668
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100669 private static class LongDecoder extends Decoder<Long> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100670
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100671 @Override
672 public byte alignment() {
673 return 8;
674 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100675
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100676 @Override
677 public Integer fixedSize() {
678 return 8;
679 }
680
681 @Override
682 public Long decode(ByteBuffer byteSlice) {
683 return byteSlice.getLong();
684 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100685 }
686
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100687 private static class DoubleDecoder extends Decoder<Double> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100688
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100689 @Override
690 public byte alignment() {
691 return 8;
692 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100693
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100694 @Override
695 public Integer fixedSize() {
696 return 8;
697 }
698
699 @Override
700 public Double decode(ByteBuffer byteSlice) {
701 return byteSlice.getDouble();
702 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100703 }
704
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100705 private static class StringDecoder extends Decoder<String> {
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100706
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100707 private final Charset charset;
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100708
Matthias Andreas Benkard34430182021-12-14 20:00:36 +0100709 public StringDecoder(Charset charset) {
710 this.charset = charset;
711 }
712
713 @Override
714 public byte alignment() {
715 return 1;
716 }
717
718 @Override
719 @Nullable
720 Integer fixedSize() {
721 return null;
722 }
723
724 @Override
725 public String decode(ByteBuffer byteSlice) {
726 byteSlice.limit(byteSlice.limit() - 1);
727 return charset.decode(byteSlice).toString();
728 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100729 }
Matthias Andreas Benkard6f993f72021-12-27 22:40:14 +0100730
731 private class MappingDecoder<U> extends Decoder<U> {
732
733 private final Function<T, U> function;
734
735 public MappingDecoder(Function<T, U> function) {
736 this.function = function;
737 }
738
739 @Override
740 public byte alignment() {
741 return Decoder.this.alignment();
742 }
743
744 @Override
745 public @Nullable Integer fixedSize() {
746 return Decoder.this.fixedSize();
747 }
748
749 @Override
750 public U decode(ByteBuffer byteSlice) {
751 return function.apply(Decoder.this.decode(byteSlice));
752 }
753 }
754
755 private class ByteOrderFixingDecoder extends Decoder<T> {
756
757 private final ByteOrder byteOrder;
758
759 public ByteOrderFixingDecoder(ByteOrder byteOrder) {
760 this.byteOrder = byteOrder;
761 }
762
763 @Override
764 public byte alignment() {
765 return Decoder.this.alignment();
766 }
767
768 @Override
769 public @Nullable Integer fixedSize() {
770 return Decoder.this.fixedSize();
771 }
772
773 @Override
774 public T decode(ByteBuffer byteSlice) {
775 var newByteSlice = byteSlice.duplicate();
776 newByteSlice.order(byteOrder);
777 return Decoder.this.decode(newByteSlice);
778 }
779 }
780
781 private static ByteBuffer slicePreservingOrder(ByteBuffer byteSlice, int index, int length) {
782 return byteSlice.slice(index, length).order(byteSlice.order());
783 }
Matthias Andreas Benkard261532a2021-12-12 20:09:27 +0100784}