2 * Copyright (c) 2019 PANTHEON.tech, s.r.o. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.yangtools.yang.data.codec.binfmt;
10 import static com.google.common.base.Verify.verifyNotNull;
11 import static java.util.Objects.requireNonNull;
12 import static org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter.UNKNOWN_SIZE;
14 import com.google.common.collect.ImmutableList;
15 import com.google.common.collect.ImmutableList.Builder;
16 import com.google.common.collect.ImmutableMap;
17 import com.google.common.collect.ImmutableSet;
18 import com.google.common.util.concurrent.UncheckedExecutionException;
19 import java.io.DataInput;
20 import java.io.IOException;
21 import java.io.StringReader;
22 import java.nio.charset.StandardCharsets;
23 import java.util.ArrayList;
24 import java.util.List;
25 import java.util.concurrent.ExecutionException;
26 import javax.xml.transform.dom.DOMSource;
27 import org.eclipse.jdt.annotation.NonNull;
28 import org.opendaylight.yangtools.concepts.Either;
29 import org.opendaylight.yangtools.concepts.WritableObjects;
30 import org.opendaylight.yangtools.util.xml.UntrustedXML;
31 import org.opendaylight.yangtools.yang.common.Decimal64;
32 import org.opendaylight.yangtools.yang.common.Empty;
33 import org.opendaylight.yangtools.yang.common.QName;
34 import org.opendaylight.yangtools.yang.common.QNameModule;
35 import org.opendaylight.yangtools.yang.common.Uint16;
36 import org.opendaylight.yangtools.yang.common.Uint32;
37 import org.opendaylight.yangtools.yang.common.Uint64;
38 import org.opendaylight.yangtools.yang.common.Uint8;
39 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
40 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
41 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
42 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
43 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
44 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
45 import org.slf4j.Logger;
46 import org.slf4j.LoggerFactory;
47 import org.xml.sax.InputSource;
48 import org.xml.sax.SAXException;
51 * Abstract base class for NormalizedNodeDataInput based on {@link PotassiumNode}, {@link PotassiumPathArgument} and
52 * {@link PotassiumValue}.
54 final class PotassiumDataInput extends AbstractNormalizedNodeDataInput {
55 private static final Logger LOG = LoggerFactory.getLogger(PotassiumDataInput.class);
57 // Known singleton objects
58 private static final @NonNull Byte INT8_0 = 0;
59 private static final @NonNull Short INT16_0 = 0;
60 private static final @NonNull Integer INT32_0 = 0;
61 private static final @NonNull Long INT64_0 = 0L;
62 private static final byte @NonNull[] BINARY_0 = new byte[0];
64 private final List<NodeIdentifier> codedNodeIdentifiers = new ArrayList<>();
65 private final List<QNameModule> codedModules = new ArrayList<>();
66 private final List<String> codedStrings = new ArrayList<>();
68 PotassiumDataInput(final DataInput input) {
73 public NormalizedNodeStreamVersion getVersion() {
74 return NormalizedNodeStreamVersion.POTASSIUM;
78 public void streamNormalizedNode(final NormalizedNodeStreamWriter writer) throws IOException {
79 streamNormalizedNode(requireNonNull(writer), null, input.readByte());
82 private void streamNormalizedNode(final NormalizedNodeStreamWriter writer, final PathArgument parent,
83 final byte nodeHeader) throws IOException {
84 switch (nodeHeader & PotassiumNode.TYPE_MASK) {
85 case PotassiumNode.NODE_LEAF:
86 streamLeaf(writer, parent, nodeHeader);
88 case PotassiumNode.NODE_CONTAINER:
89 streamContainer(writer, nodeHeader);
91 case PotassiumNode.NODE_LIST:
92 streamList(writer, nodeHeader);
94 case PotassiumNode.NODE_MAP:
95 streamMap(writer, nodeHeader);
97 case PotassiumNode.NODE_MAP_ORDERED:
98 streamMapOrdered(writer, nodeHeader);
100 case PotassiumNode.NODE_LEAFSET:
101 streamLeafset(writer, nodeHeader);
103 case PotassiumNode.NODE_LEAFSET_ORDERED:
104 streamLeafsetOrdered(writer, nodeHeader);
106 case PotassiumNode.NODE_CHOICE:
107 streamChoice(writer, nodeHeader);
109 case PotassiumNode.NODE_ANYXML:
110 streamAnyxml(writer, nodeHeader);
112 case PotassiumNode.NODE_LIST_ENTRY:
113 streamListEntry(writer, parent, nodeHeader);
115 case PotassiumNode.NODE_LEAFSET_ENTRY:
116 streamLeafsetEntry(writer, parent, nodeHeader);
118 case PotassiumNode.NODE_MAP_ENTRY:
119 streamMapEntry(writer, parent, nodeHeader);
122 throw new InvalidNormalizedNodeStreamException("Unexpected node header " + nodeHeader);
126 private void streamAnyxml(final NormalizedNodeStreamWriter writer, final byte nodeHeader) throws IOException {
127 final NodeIdentifier identifier = decodeNodeIdentifier(nodeHeader);
128 LOG.trace("Streaming anyxml node {}", identifier);
130 final DOMSource value = readDOMSource();
131 if (writer.startAnyxmlNode(identifier, DOMSource.class)) {
132 writer.domSourceValue(value);
137 private void streamChoice(final NormalizedNodeStreamWriter writer, final byte nodeHeader) throws IOException {
138 final NodeIdentifier identifier = decodeNodeIdentifier(nodeHeader);
139 LOG.trace("Streaming choice node {}", identifier);
140 writer.startChoiceNode(identifier, UNKNOWN_SIZE);
141 commonStreamContainer(writer, identifier);
144 private void streamContainer(final NormalizedNodeStreamWriter writer, final byte nodeHeader) throws IOException {
145 final NodeIdentifier identifier = decodeNodeIdentifier(nodeHeader);
146 LOG.trace("Streaming container node {}", identifier);
147 writer.startContainerNode(identifier, UNKNOWN_SIZE);
148 commonStreamContainer(writer, identifier);
151 private void streamLeaf(final NormalizedNodeStreamWriter writer, final PathArgument parent, final byte nodeHeader)
153 final NodeIdentifier identifier = decodeNodeIdentifier(nodeHeader);
154 LOG.trace("Streaming leaf node {}", identifier);
155 writer.startLeafNode(identifier);
158 if ((nodeHeader & PotassiumNode.PREDICATE_ONE) == PotassiumNode.PREDICATE_ONE) {
159 if (!(parent instanceof NodeIdentifierWithPredicates nip)) {
160 throw new InvalidNormalizedNodeStreamException("Invalid predicate leaf " + identifier + " in parent "
164 value = nip.getValue(identifier.getNodeType());
166 throw new InvalidNormalizedNodeStreamException("Failed to find predicate leaf " + identifier
167 + " in parent " + parent);
170 value = readLeafValue();
173 writer.scalarValue(value);
177 private void streamLeafset(final NormalizedNodeStreamWriter writer, final byte nodeHeader) throws IOException {
178 final NodeIdentifier identifier = decodeNodeIdentifier(nodeHeader);
179 LOG.trace("Streaming leaf set node {}", identifier);
180 writer.startLeafSet(identifier, UNKNOWN_SIZE);
181 commonStreamContainer(writer, identifier);
184 private void streamLeafsetOrdered(final NormalizedNodeStreamWriter writer, final byte nodeHeader)
186 final NodeIdentifier identifier = decodeNodeIdentifier(nodeHeader);
187 LOG.trace("Streaming ordered leaf set node {}", identifier);
188 writer.startOrderedLeafSet(identifier, UNKNOWN_SIZE);
190 commonStreamContainer(writer, identifier);
193 private void streamLeafsetEntry(final NormalizedNodeStreamWriter writer, final PathArgument parent,
194 final byte nodeHeader) throws IOException {
195 final NodeIdentifier nodeId = decodeNodeIdentifier(nodeHeader, parent);
196 final Object value = readLeafValue();
197 final NodeWithValue<Object> leafIdentifier = new NodeWithValue<>(nodeId.getNodeType(), value);
198 LOG.trace("Streaming leaf set entry node {}", leafIdentifier);
199 writer.startLeafSetEntryNode(leafIdentifier);
200 writer.scalarValue(value);
204 private void streamList(final NormalizedNodeStreamWriter writer, final byte nodeHeader) throws IOException {
205 final NodeIdentifier identifier = decodeNodeIdentifier(nodeHeader);
206 writer.startUnkeyedList(identifier, UNKNOWN_SIZE);
207 commonStreamContainer(writer, identifier);
210 private void streamListEntry(final NormalizedNodeStreamWriter writer, final PathArgument parent,
211 final byte nodeHeader) throws IOException {
212 final NodeIdentifier identifier = decodeNodeIdentifier(nodeHeader, parent);
213 LOG.trace("Streaming unkeyed list item node {}", identifier);
214 writer.startUnkeyedListItem(identifier, UNKNOWN_SIZE);
215 commonStreamContainer(writer, identifier);
218 private void streamMap(final NormalizedNodeStreamWriter writer, final byte nodeHeader) throws IOException {
219 final NodeIdentifier identifier = decodeNodeIdentifier(nodeHeader);
220 LOG.trace("Streaming map node {}", identifier);
221 writer.startMapNode(identifier, UNKNOWN_SIZE);
222 commonStreamContainer(writer, identifier);
225 private void streamMapOrdered(final NormalizedNodeStreamWriter writer, final byte nodeHeader) throws IOException {
226 final NodeIdentifier identifier = decodeNodeIdentifier(nodeHeader);
227 LOG.trace("Streaming ordered map node {}", identifier);
228 writer.startOrderedMapNode(identifier, UNKNOWN_SIZE);
229 commonStreamContainer(writer, identifier);
232 private void streamMapEntry(final NormalizedNodeStreamWriter writer, final PathArgument parent,
233 final byte nodeHeader) throws IOException {
234 final NodeIdentifier nodeId = decodeNodeIdentifier(nodeHeader, parent);
236 final int size = switch (mask(nodeHeader, PotassiumNode.PREDICATE_MASK)) {
237 case PotassiumNode.PREDICATE_ZERO -> 0;
238 case PotassiumNode.PREDICATE_ONE -> 1;
239 case PotassiumNode.PREDICATE_1B -> input.readUnsignedByte();
240 case PotassiumNode.PREDICATE_4B -> input.readInt();
242 // ISE on purpose: this should never ever happen
243 throw new IllegalStateException("Failed to decode NodeIdentifierWithPredicates size from header "
246 final NodeIdentifierWithPredicates identifier = readNodeIdentifierWithPredicates(nodeId.getNodeType(), size);
247 LOG.trace("Streaming map entry node {}", identifier);
248 writer.startMapEntryNode(identifier, UNKNOWN_SIZE);
249 commonStreamContainer(writer, identifier);
252 private void commonStreamContainer(final NormalizedNodeStreamWriter writer, final PathArgument parent)
254 for (byte nodeType = input.readByte(); nodeType != PotassiumNode.NODE_END; nodeType = input.readByte()) {
255 streamNormalizedNode(writer, parent, nodeType);
260 private @NonNull NodeIdentifier decodeNodeIdentifier() throws IOException {
261 final QNameModule module = decodeQNameModule();
262 final String localName = readRefString();
263 final NodeIdentifier nodeId;
265 nodeId = QNameFactory.getNodeIdentifier(module, localName);
266 } catch (ExecutionException e) {
267 throw new InvalidNormalizedNodeStreamException("Illegal QName module=" + module + " localName="
271 codedNodeIdentifiers.add(nodeId);
275 private NodeIdentifier decodeNodeIdentifier(final byte nodeHeader) throws IOException {
276 return decodeNodeIdentifier(nodeHeader, null);
279 private NodeIdentifier decodeNodeIdentifier(final byte nodeHeader, final PathArgument parent) throws IOException {
281 switch (nodeHeader & PotassiumNode.ADDR_MASK) {
282 case PotassiumNode.ADDR_DEFINE:
283 return readNodeIdentifier();
284 case PotassiumNode.ADDR_LOOKUP_1B:
285 index = input.readUnsignedByte();
287 case PotassiumNode.ADDR_LOOKUP_4B:
288 index = input.readInt();
290 case PotassiumNode.ADDR_PARENT:
291 if (parent instanceof NodeIdentifier nid) {
294 throw new InvalidNormalizedNodeStreamException("Invalid node identifier reference to parent " + parent);
296 throw new InvalidNormalizedNodeStreamException("Unexpected node identifier addressing in header "
301 return codedNodeIdentifiers.get(index);
302 } catch (IndexOutOfBoundsException e) {
303 throw new InvalidNormalizedNodeStreamException("Invalid QName reference " + index, e);
308 public YangInstanceIdentifier readYangInstanceIdentifier() throws IOException {
309 final byte type = input.readByte();
310 if (type == PotassiumValue.YIID) {
311 return readYangInstanceIdentifier(input.readInt());
312 } else if (type >= PotassiumValue.YIID_0) {
313 // Note 'byte' is range limited, so it is always '&& type <= PotassiumValue.YIID_31'
314 return readYangInstanceIdentifier(type - PotassiumValue.YIID_0);
316 throw new InvalidNormalizedNodeStreamException("Unexpected YangInstanceIdentifier type " + type);
320 private @NonNull YangInstanceIdentifier readYangInstanceIdentifier(final int size) throws IOException {
322 final Builder<PathArgument> builder = ImmutableList.builderWithExpectedSize(size);
323 for (int i = 0; i < size; ++i) {
324 builder.add(readPathArgument());
326 return YangInstanceIdentifier.of(builder.build());
327 } else if (size == 0) {
328 return YangInstanceIdentifier.of();
330 throw new InvalidNormalizedNodeStreamException("Invalid YangInstanceIdentifier size " + size);
335 public QName readQName() throws IOException {
336 final byte type = input.readByte();
337 return switch (type) {
338 case PotassiumValue.QNAME -> decodeQName();
339 case PotassiumValue.QNAME_REF_1B -> decodeQNameRef1();
340 case PotassiumValue.QNAME_REF_2B -> decodeQNameRef2();
341 case PotassiumValue.QNAME_REF_4B -> decodeQNameRef4();
342 default -> throw new InvalidNormalizedNodeStreamException("Unexpected QName type " + type);
347 public PathArgument readPathArgument() throws IOException {
348 final byte header = input.readByte();
349 return switch (header & PotassiumPathArgument.TYPE_MASK) {
350 case PotassiumPathArgument.NODE_IDENTIFIER -> {
351 verifyPathIdentifierOnly(header);
352 yield readNodeIdentifier(header);
354 case PotassiumPathArgument.NODE_IDENTIFIER_WITH_PREDICATES -> readNodeIdentifierWithPredicates(header);
355 case PotassiumPathArgument.NODE_WITH_VALUE -> {
356 verifyPathIdentifierOnly(header);
357 yield readNodeWithValue(header);
359 default -> throw new InvalidNormalizedNodeStreamException("Unexpected PathArgument header " + header);
364 @Deprecated(since = "11.0.0", forRemoval = true)
365 public Either<PathArgument, LegacyPathArgument> readLegacyPathArgument() throws IOException {
366 return Either.ofFirst(readPathArgument());
369 private @NonNull NodeIdentifier readNodeIdentifier() throws IOException {
370 return decodeNodeIdentifier();
373 private @NonNull NodeIdentifier readNodeIdentifier(final byte header) throws IOException {
374 return switch (header & PotassiumPathArgument.QNAME_MASK) {
375 case PotassiumPathArgument.QNAME_DEF -> decodeNodeIdentifier();
376 case PotassiumPathArgument.QNAME_REF_1B -> decodeNodeIdentifierRef1();
377 case PotassiumPathArgument.QNAME_REF_2B -> decodeNodeIdentifierRef2();
378 case PotassiumPathArgument.QNAME_REF_4B -> decodeNodeIdentifierRef4();
379 default -> throw new InvalidNormalizedNodeStreamException("Invalid QName coding in " + header);
383 private @NonNull NodeIdentifierWithPredicates readNodeIdentifierWithPredicates(final byte header)
385 final QName qname = readNodeIdentifier(header).getNodeType();
386 return switch (mask(header, PotassiumPathArgument.SIZE_MASK)) {
387 case PotassiumPathArgument.SIZE_1B -> readNodeIdentifierWithPredicates(qname, input.readUnsignedByte());
388 case PotassiumPathArgument.SIZE_2B -> readNodeIdentifierWithPredicates(qname, input.readUnsignedShort());
389 case PotassiumPathArgument.SIZE_4B -> readNodeIdentifierWithPredicates(qname, input.readInt());
390 default -> readNodeIdentifierWithPredicates(qname, rshift(header, PotassiumPathArgument.SIZE_SHIFT));
394 private @NonNull NodeIdentifierWithPredicates readNodeIdentifierWithPredicates(final QName qname, final int size)
397 return NodeIdentifierWithPredicates.of(qname, readQName(), readLeafValue());
398 } else if (size > 1) {
399 final ImmutableMap.Builder<QName, Object> builder = ImmutableMap.builderWithExpectedSize(size);
400 for (int i = 0; i < size; ++i) {
401 builder.put(readQName(), readLeafValue());
403 return NodeIdentifierWithPredicates.of(qname, builder.build());
404 } else if (size == 0) {
405 return NodeIdentifierWithPredicates.of(qname);
407 throw new InvalidNormalizedNodeStreamException("Invalid predicate count " + size);
411 private @NonNull NodeWithValue<?> readNodeWithValue(final byte header) throws IOException {
412 final QName qname = readNodeIdentifier(header).getNodeType();
413 return new NodeWithValue<>(qname, readLeafValue());
416 private static void verifyPathIdentifierOnly(final byte header) throws InvalidNormalizedNodeStreamException {
417 if (mask(header, PotassiumPathArgument.SIZE_MASK) != 0) {
418 throw new InvalidNormalizedNodeStreamException("Invalid path argument header " + header);
422 private @NonNull NodeIdentifier decodeNodeIdentifierRef1() throws IOException {
423 return lookupNodeIdentifier(input.readUnsignedByte());
426 private @NonNull NodeIdentifier decodeNodeIdentifierRef2() throws IOException {
427 return lookupNodeIdentifier(input.readUnsignedShort() + 256);
430 private @NonNull NodeIdentifier decodeNodeIdentifierRef4() throws IOException {
431 return lookupNodeIdentifier(input.readInt());
434 private @NonNull QName decodeQName() throws IOException {
435 return decodeNodeIdentifier().getNodeType();
438 private @NonNull QName decodeQNameRef1() throws IOException {
439 return lookupQName(input.readUnsignedByte());
442 private @NonNull QName decodeQNameRef2() throws IOException {
443 return lookupQName(input.readUnsignedShort() + 256);
446 private @NonNull QName decodeQNameRef4() throws IOException {
447 return lookupQName(input.readInt());
450 private @NonNull QNameModule decodeQNameModule() throws IOException {
451 final byte type = input.readByte();
454 case PotassiumValue.MODREF_1B:
455 index = input.readUnsignedByte();
457 case PotassiumValue.MODREF_2B:
458 index = input.readUnsignedShort() + 256;
460 case PotassiumValue.MODREF_4B:
461 index = input.readInt();
464 return decodeQNameModuleDef(type);
468 return codedModules.get(index);
469 } catch (IndexOutOfBoundsException e) {
470 throw new InvalidNormalizedNodeStreamException("Invalid QNameModule reference " + index, e);
474 // QNameModule definition, i.e. two encoded strings
475 private @NonNull QNameModule decodeQNameModuleDef(final byte type) throws IOException {
476 final String namespace = readRefString(type);
478 final byte refType = input.readByte();
479 final String revision = refType == PotassiumValue.STRING_EMPTY ? null : readRefString(refType);
480 final QNameModule module;
482 module = QNameFactory.createModule(namespace, revision);
483 } catch (UncheckedExecutionException e) {
484 throw new InvalidNormalizedNodeStreamException("Illegal QNameModule ns=" + namespace + " rev=" + revision,
488 codedModules.add(module);
492 private @NonNull String readRefString() throws IOException {
493 return readRefString(input.readByte());
496 private @NonNull String readRefString(final byte type) throws IOException {
499 case PotassiumValue.STRING_REF_1B:
500 return lookupString(input.readUnsignedByte());
501 case PotassiumValue.STRING_REF_2B:
502 return lookupString(input.readUnsignedShort() + 256);
503 case PotassiumValue.STRING_REF_4B:
504 return lookupString(input.readInt());
505 case PotassiumValue.STRING_EMPTY:
507 case PotassiumValue.STRING_2B:
510 case PotassiumValue.STRING_4B:
513 case PotassiumValue.STRING_CHARS:
514 str = readCharsString();
516 case PotassiumValue.STRING_UTF:
517 str = input.readUTF();
520 throw new InvalidNormalizedNodeStreamException("Unexpected String type " + type);
523 // TODO: consider interning Strings -- that would help with bits, but otherwise it's probably not worth it
524 codedStrings.add(verifyNotNull(str));
528 private @NonNull String readString() throws IOException {
529 final byte type = input.readByte();
530 return switch (type) {
531 case PotassiumValue.STRING_EMPTY -> "";
532 case PotassiumValue.STRING_UTF -> input.readUTF();
533 case PotassiumValue.STRING_2B -> readString2();
534 case PotassiumValue.STRING_4B -> readString4();
535 case PotassiumValue.STRING_CHARS -> readCharsString();
536 default -> throw new InvalidNormalizedNodeStreamException("Unexpected String type " + type);
540 private @NonNull String readString2() throws IOException {
541 return readByteString(input.readUnsignedShort());
544 private @NonNull String readString4() throws IOException {
545 return readByteString(input.readInt());
548 private @NonNull String readByteString(final int size) throws IOException {
550 final byte[] bytes = new byte[size];
551 input.readFully(bytes);
552 return new String(bytes, StandardCharsets.UTF_8);
553 } else if (size == 0) {
556 throw new InvalidNormalizedNodeStreamException("Invalid String bytes length " + size);
560 private @NonNull String readCharsString() throws IOException {
561 final int size = input.readInt();
563 final char[] chars = new char[size];
564 for (int i = 0; i < size; ++i) {
565 chars[i] = input.readChar();
567 return String.valueOf(chars);
568 } else if (size == 0) {
571 throw new InvalidNormalizedNodeStreamException("Invalid String chars length " + size);
575 private @NonNull NodeIdentifier lookupNodeIdentifier(final int index) throws InvalidNormalizedNodeStreamException {
577 return codedNodeIdentifiers.get(index);
578 } catch (IndexOutOfBoundsException e) {
579 throw new InvalidNormalizedNodeStreamException("Invalid QName reference " + index, e);
583 private @NonNull QName lookupQName(final int index) throws InvalidNormalizedNodeStreamException {
584 return lookupNodeIdentifier(index).getNodeType();
587 private @NonNull String lookupString(final int index) throws InvalidNormalizedNodeStreamException {
589 return codedStrings.get(index);
590 } catch (IndexOutOfBoundsException e) {
591 throw new InvalidNormalizedNodeStreamException("Invalid String reference " + index, e);
595 private @NonNull DOMSource readDOMSource() throws IOException {
596 final String str = readString();
598 return new DOMSource(UntrustedXML.newDocumentBuilder().parse(new InputSource(new StringReader(str)))
599 .getDocumentElement());
600 } catch (SAXException e) {
601 throw new IOException("Error parsing XML: " + str, e);
605 private @NonNull Object readLeafValue() throws IOException {
606 final byte type = input.readByte();
608 case PotassiumValue.BOOLEAN_FALSE:
609 return Boolean.FALSE;
610 case PotassiumValue.BOOLEAN_TRUE:
612 case PotassiumValue.EMPTY:
613 return Empty.value();
614 case PotassiumValue.INT8:
615 return input.readByte();
616 case PotassiumValue.INT8_0:
618 case PotassiumValue.INT16:
619 return input.readShort();
620 case PotassiumValue.INT16_0:
622 case PotassiumValue.INT32:
623 return input.readInt();
624 case PotassiumValue.INT32_0:
626 case PotassiumValue.INT32_2B:
627 return input.readShort() & 0xFFFF;
628 case PotassiumValue.INT64:
629 return input.readLong();
630 case PotassiumValue.INT64_0:
632 case PotassiumValue.INT64_4B:
633 return input.readInt() & 0xFFFFFFFFL;
634 case PotassiumValue.UINT8:
635 return Uint8.fromByteBits(input.readByte());
636 case PotassiumValue.UINT8_0:
638 case PotassiumValue.UINT16:
639 return Uint16.fromShortBits(input.readShort());
640 case PotassiumValue.UINT16_0:
642 case PotassiumValue.UINT32:
643 return Uint32.fromIntBits(input.readInt());
644 case PotassiumValue.UINT32_0:
646 case PotassiumValue.UINT32_2B:
647 return Uint32.fromIntBits(input.readShort() & 0xFFFF);
648 case PotassiumValue.UINT64:
649 return Uint64.fromLongBits(input.readLong());
650 case PotassiumValue.UINT64_0:
652 case PotassiumValue.UINT64_4B:
653 return Uint64.fromLongBits(input.readInt() & 0xFFFFFFFFL);
654 case PotassiumValue.DECIMAL64:
655 return Decimal64.of(input.readByte(), WritableObjects.readLong(input));
656 case PotassiumValue.STRING_EMPTY:
658 case PotassiumValue.STRING_UTF:
659 return input.readUTF();
660 case PotassiumValue.STRING_2B:
661 return readString2();
662 case PotassiumValue.STRING_4B:
663 return readString4();
664 case PotassiumValue.STRING_CHARS:
665 return readCharsString();
666 case PotassiumValue.BINARY_0:
668 case PotassiumValue.BINARY_1B:
669 return readBinary(128 + input.readUnsignedByte());
670 case PotassiumValue.BINARY_2B:
671 return readBinary(384 + input.readUnsignedShort());
672 case PotassiumValue.BINARY_4B:
673 return readBinary(input.readInt());
674 case PotassiumValue.YIID_0:
675 return YangInstanceIdentifier.of();
676 case PotassiumValue.YIID:
677 return readYangInstanceIdentifier(input.readInt());
678 case PotassiumValue.QNAME:
679 return decodeQName();
680 case PotassiumValue.QNAME_REF_1B:
681 return decodeQNameRef1();
682 case PotassiumValue.QNAME_REF_2B:
683 return decodeQNameRef2();
684 case PotassiumValue.QNAME_REF_4B:
685 return decodeQNameRef4();
686 case PotassiumValue.BITS_0:
687 return ImmutableSet.of();
688 case PotassiumValue.BITS_1B:
689 return readBits(input.readUnsignedByte() + 29);
690 case PotassiumValue.BITS_2B:
691 return readBits(input.readUnsignedShort() + 285);
692 case PotassiumValue.BITS_4B:
693 return readBits(input.readInt());
696 if (type > PotassiumValue.BINARY_0 && type <= PotassiumValue.BINARY_127) {
697 return readBinary(type - PotassiumValue.BINARY_0);
698 } else if (type > PotassiumValue.BITS_0 && type < PotassiumValue.BITS_1B) {
699 return readBits(type - PotassiumValue.BITS_0);
700 } else if (type > PotassiumValue.YIID_0) {
701 // Note 'byte' is range limited, so it is always '&& type <= PotassiumValue.YIID_31'
702 return readYangInstanceIdentifier(type - PotassiumValue.YIID_0);
704 throw new InvalidNormalizedNodeStreamException("Invalid value type " + type);
709 private byte @NonNull [] readBinary(final int size) throws IOException {
711 final byte[] ret = new byte[size];
712 input.readFully(ret);
714 } else if (size == 0) {
717 throw new InvalidNormalizedNodeStreamException("Invalid binary length " + size);
721 private @NonNull ImmutableSet<String> readBits(final int size) throws IOException {
723 final ImmutableSet.Builder<String> builder = ImmutableSet.builder();
724 for (int i = 0; i < size; ++i) {
725 builder.add(readRefString());
727 return builder.build();
728 } else if (size == 0) {
729 return ImmutableSet.of();
731 throw new InvalidNormalizedNodeStreamException("Invalid bits length " + size);
735 private static byte mask(final byte header, final byte mask) {
736 return (byte) (header & mask);
739 private static int rshift(final byte header, final byte shift) {
740 return (header & 0xFF) >>> shift;