Remove support for inputs older than Magnesium 57/108257/2
authorRobert Varga <robert.varga@pantheon.tech>
Thu, 5 Oct 2023 15:17:29 +0000 (17:17 +0200)
committerRobert Varga <robert.varga@pantheon.tech>
Mon, 9 Oct 2023 08:49:09 +0000 (10:49 +0200)
We have a number of obsolete formats here, which are not efficient or
tested. Eliminate LITHIUM,NEON_SR2 and SODIUM_SR1 support.

JIRA: YANGTOOLS-1548
Change-Id: I973916d2ffb25e219380c854dcbe2d86d0b60337
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
14 files changed:
codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/AbstractLithiumDataInput.java [deleted file]
codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/AbstractMagnesiumDataInput.java [deleted file]
codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/LithiumNode.java [deleted file]
codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/LithiumNormalizedNodeInputStreamReader.java [deleted file]
codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/LithiumPathArgument.java [deleted file]
codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/LithiumTokens.java [deleted file]
codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/LithiumValue.java [deleted file]
codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/MagnesiumDataInput.java
codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/NeonSR2NormalizedNodeInputStreamReader.java [deleted file]
codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/NeonSR2Tokens.java [deleted file]
codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/NormalizedNodeStreamVersion.java
codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/SodiumSR1DataInput.java [deleted file]
codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/TokenTypes.java
codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/VersionedNormalizedNodeDataInput.java

diff --git a/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/AbstractLithiumDataInput.java b/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/AbstractLithiumDataInput.java
deleted file mode 100644 (file)
index 9953d02..0000000
+++ /dev/null
@@ -1,390 +0,0 @@
-/*
- * Copyright (c) 2014, 2015 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.yangtools.yang.data.codec.binfmt;
-
-import static java.util.Objects.requireNonNull;
-
-import com.google.common.base.Strings;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableList.Builder;
-import com.google.common.collect.ImmutableSet;
-import java.io.DataInput;
-import java.io.IOException;
-import java.io.StringReader;
-import java.math.BigInteger;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.transform.dom.DOMSource;
-import org.eclipse.jdt.annotation.NonNull;
-import org.opendaylight.yangtools.concepts.Either;
-import org.opendaylight.yangtools.util.ImmutableOffsetMapTemplate;
-import org.opendaylight.yangtools.yang.common.Decimal64;
-import org.opendaylight.yangtools.yang.common.Empty;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
-import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.w3c.dom.Element;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
-
-/**
- * NormalizedNodeInputStreamReader reads the byte stream and constructs the normalized node including its children
- * nodes. This process goes in recursive manner, where each NodeTypes object signifies the start of the object, except
- * END_NODE. If a node can have children, then that node's end is calculated based on appearance of END_NODE.
- */
-abstract class AbstractLithiumDataInput extends AbstractLegacyDataInput {
-    private static final Logger LOG = LoggerFactory.getLogger(AbstractLithiumDataInput.class);
-
-    private final List<String> codedStringMap = new ArrayList<>();
-
-    private QName lastLeafSetQName;
-
-    AbstractLithiumDataInput(final DataInput input) {
-        super(input);
-    }
-
-    @Override
-    public final void streamNormalizedNode(final NormalizedNodeStreamWriter writer) throws IOException {
-        streamNormalizedNode(requireNonNull(writer), input.readByte());
-    }
-
-    private void streamNormalizedNode(final NormalizedNodeStreamWriter writer, final byte nodeType) throws IOException {
-        switch (nodeType) {
-            case LithiumNode.ANY_XML_NODE -> streamAnyxml(writer);
-            case LithiumNode.AUGMENTATION_NODE -> streamAugmentation(writer);
-            case LithiumNode.CHOICE_NODE -> streamChoice(writer);
-            case LithiumNode.CONTAINER_NODE -> streamContainer(writer);
-            case LithiumNode.LEAF_NODE -> streamLeaf(writer);
-            case LithiumNode.LEAF_SET -> streamLeafSet(writer);
-            case LithiumNode.ORDERED_LEAF_SET -> streamOrderedLeafSet(writer);
-            case LithiumNode.LEAF_SET_ENTRY_NODE -> streamLeafSetEntry(writer);
-            case LithiumNode.MAP_ENTRY_NODE -> streamMapEntry(writer);
-            case LithiumNode.MAP_NODE -> streamMap(writer);
-            case LithiumNode.ORDERED_MAP_NODE -> streamOrderedMap(writer);
-            case LithiumNode.UNKEYED_LIST -> streamUnkeyedList(writer);
-            case LithiumNode.UNKEYED_LIST_ITEM -> streamUnkeyedListItem(writer);
-            default -> throw new InvalidNormalizedNodeStreamException("Unexpected node " + nodeType);
-        }
-    }
-
-    private void streamAnyxml(final NormalizedNodeStreamWriter writer) throws IOException {
-        final NodeIdentifier identifier = readNodeIdentifier();
-        LOG.trace("Streaming anyxml node {}", identifier);
-
-        final DOMSource value = readDOMSource();
-        if (writer.startAnyxmlNode(identifier, DOMSource.class)) {
-            writer.domSourceValue(value);
-            writer.endNode();
-        }
-    }
-
-    private void streamAugmentation(final NormalizedNodeStreamWriter writer) throws IOException {
-        final var augIdentifier = readAugmentationIdentifier();
-        LOG.trace("Streaming augmentation node {}", augIdentifier);
-        for (byte nodeType = input.readByte(); nodeType != LithiumNode.END_NODE; nodeType = input.readByte()) {
-            streamNormalizedNode(writer, nodeType);
-        }
-    }
-
-    private void streamChoice(final NormalizedNodeStreamWriter writer) throws IOException {
-        final NodeIdentifier identifier = readNodeIdentifier();
-        LOG.trace("Streaming choice node {}", identifier);
-        writer.startChoiceNode(identifier, NormalizedNodeStreamWriter.UNKNOWN_SIZE);
-        commonStreamContainer(writer);
-    }
-
-    private void streamContainer(final NormalizedNodeStreamWriter writer) throws IOException {
-        final NodeIdentifier identifier = readNodeIdentifier();
-        LOG.trace("Streaming container node {}", identifier);
-        writer.startContainerNode(identifier, NormalizedNodeStreamWriter.UNKNOWN_SIZE);
-        commonStreamContainer(writer);
-    }
-
-    private void streamLeaf(final NormalizedNodeStreamWriter writer) throws IOException {
-        startLeaf(writer);
-        endLeaf(writer, readObject());
-    }
-
-    // Leaf inside a MapEntryNode, it can potentially be a key leaf, in which case we want to de-duplicate values.
-    private void streamLeaf(final NormalizedNodeStreamWriter writer, final NodeIdentifierWithPredicates entryId)
-            throws IOException {
-        final NodeIdentifier identifier = startLeaf(writer);
-        final Object value = readObject();
-        final Object entryValue = entryId.getValue(identifier.getNodeType());
-        endLeaf(writer, entryValue == null ? value : entryValue);
-    }
-
-    private NodeIdentifier startLeaf(final NormalizedNodeStreamWriter writer) throws IOException {
-        final NodeIdentifier identifier = readNodeIdentifier();
-        LOG.trace("Streaming leaf node {}", identifier);
-        writer.startLeafNode(identifier);
-        return identifier;
-    }
-
-    private static void endLeaf(final NormalizedNodeStreamWriter writer, final Object value) throws IOException {
-        writer.scalarValue(value);
-        writer.endNode();
-    }
-
-    private void streamLeafSet(final NormalizedNodeStreamWriter writer) throws IOException {
-        final NodeIdentifier identifier = readNodeIdentifier();
-        LOG.trace("Streaming leaf set node {}", identifier);
-        writer.startLeafSet(identifier, NormalizedNodeStreamWriter.UNKNOWN_SIZE);
-        commonStreamLeafSet(writer, identifier);
-    }
-
-    private void streamOrderedLeafSet(final NormalizedNodeStreamWriter writer) throws IOException {
-        final NodeIdentifier identifier = readNodeIdentifier();
-        LOG.trace("Streaming ordered leaf set node {}", identifier);
-        writer.startOrderedLeafSet(identifier, NormalizedNodeStreamWriter.UNKNOWN_SIZE);
-        commonStreamLeafSet(writer, identifier);
-    }
-
-    private void commonStreamLeafSet(final NormalizedNodeStreamWriter writer, final NodeIdentifier identifier)
-            throws IOException {
-        lastLeafSetQName = identifier.getNodeType();
-        try {
-            commonStreamContainer(writer);
-        } finally {
-            // Make sure we never leak this
-            lastLeafSetQName = null;
-        }
-    }
-
-    private void streamLeafSetEntry(final NormalizedNodeStreamWriter writer) throws IOException {
-        final QName name = lastLeafSetQName != null ? lastLeafSetQName : readQName();
-        final Object value = readObject();
-        final NodeWithValue<Object> leafIdentifier = new NodeWithValue<>(name, value);
-        LOG.trace("Streaming leaf set entry node {}, value {}", leafIdentifier, value);
-        writer.startLeafSetEntryNode(leafIdentifier);
-        writer.scalarValue(value);
-        writer.endNode();
-    }
-
-    private void streamMap(final NormalizedNodeStreamWriter writer) throws IOException {
-        final NodeIdentifier identifier = readNodeIdentifier();
-        LOG.trace("Streaming map node {}", identifier);
-        writer.startMapNode(identifier, NormalizedNodeStreamWriter.UNKNOWN_SIZE);
-        commonStreamContainer(writer);
-    }
-
-    private void streamOrderedMap(final NormalizedNodeStreamWriter writer) throws IOException {
-        final NodeIdentifier identifier = readNodeIdentifier();
-        LOG.trace("Streaming ordered map node {}", identifier);
-        writer.startOrderedMapNode(identifier, NormalizedNodeStreamWriter.UNKNOWN_SIZE);
-        commonStreamContainer(writer);
-    }
-
-    private void streamMapEntry(final NormalizedNodeStreamWriter writer) throws IOException {
-        final NodeIdentifierWithPredicates entryIdentifier = readNormalizedNodeWithPredicates();
-        LOG.trace("Streaming map entry node {}", entryIdentifier);
-        writer.startMapEntryNode(entryIdentifier, NormalizedNodeStreamWriter.UNKNOWN_SIZE);
-
-        // Same loop as commonStreamContainer(), but ...
-        for (byte nodeType = input.readByte(); nodeType != LithiumNode.END_NODE; nodeType = input.readByte()) {
-            if (nodeType == LithiumNode.LEAF_NODE) {
-                // ... leaf nodes may need de-duplication
-                streamLeaf(writer, entryIdentifier);
-            } else {
-                streamNormalizedNode(writer, nodeType);
-            }
-        }
-        writer.endNode();
-    }
-
-    private void streamUnkeyedList(final NormalizedNodeStreamWriter writer) throws IOException {
-        final NodeIdentifier identifier = readNodeIdentifier();
-        LOG.trace("Streaming unkeyed list node {}", identifier);
-        writer.startUnkeyedList(identifier, NormalizedNodeStreamWriter.UNKNOWN_SIZE);
-        commonStreamContainer(writer);
-    }
-
-    private void streamUnkeyedListItem(final NormalizedNodeStreamWriter writer) throws IOException {
-        final NodeIdentifier identifier = readNodeIdentifier();
-        LOG.trace("Streaming unkeyed list item node {}", identifier);
-        writer.startUnkeyedListItem(identifier, NormalizedNodeStreamWriter.UNKNOWN_SIZE);
-        commonStreamContainer(writer);
-    }
-
-    private void commonStreamContainer(final NormalizedNodeStreamWriter writer) throws IOException {
-        for (byte nodeType = input.readByte(); nodeType != LithiumNode.END_NODE; nodeType = input.readByte()) {
-            streamNormalizedNode(writer, nodeType);
-        }
-        writer.endNode();
-    }
-
-    private DOMSource readDOMSource() throws IOException {
-        String xml = readObject().toString();
-        try {
-            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
-            factory.setNamespaceAware(true);
-            Element node = factory.newDocumentBuilder().parse(
-                    new InputSource(new StringReader(xml))).getDocumentElement();
-            return new DOMSource(node);
-        } catch (SAXException | ParserConfigurationException e) {
-            throw new IOException("Error parsing XML: " + xml, e);
-        }
-    }
-
-    final QName defaultReadQName() throws IOException {
-        // Read in the same sequence of writing
-        String localName = readCodedString();
-        String namespace = readCodedString();
-        String revision = Strings.emptyToNull(readCodedString());
-
-        return QNameFactory.create(localName, namespace, revision);
-    }
-
-    final String readCodedString() throws IOException {
-        final byte valueType = input.readByte();
-        return switch (valueType) {
-            case LithiumTokens.IS_NULL_VALUE -> null;
-            case LithiumTokens.IS_CODE_VALUE -> {
-                final int code = input.readInt();
-                try {
-                    yield codedStringMap.get(code);
-                } catch (IndexOutOfBoundsException e) {
-                    throw new IOException("String code " + code + " was not found", e);
-                }
-            }
-            case LithiumTokens.IS_STRING_VALUE -> {
-                final String value = input.readUTF().intern();
-                codedStringMap.add(value);
-                yield value;
-            }
-            default -> throw new IOException("Unhandled string value type " + valueType);
-        };
-    }
-
-    private ImmutableSet<QName> readQNameSet() throws IOException {
-        // Read the children count
-        final int count = input.readInt();
-        final var children = ImmutableSet.<QName>builderWithExpectedSize(count);
-        for (int i = 0; i < count; i++) {
-            children.add(readQName());
-        }
-        return children.build();
-    }
-
-    abstract @NonNull LegacyAugmentationIdentifier readAugmentationIdentifier() throws IOException;
-
-    abstract @NonNull NodeIdentifier readNodeIdentifier() throws IOException;
-
-    final @NonNull LegacyAugmentationIdentifier defaultReadAugmentationIdentifier() throws IOException {
-        return new LegacyAugmentationIdentifier(readQNameSet());
-    }
-
-    private @NonNull NodeIdentifierWithPredicates readNormalizedNodeWithPredicates() throws IOException {
-        final QName qname = readQName();
-        final int count = input.readInt();
-        switch (count) {
-            case 0:
-                return NodeIdentifierWithPredicates.of(qname);
-            case 1:
-                return NodeIdentifierWithPredicates.of(qname, readQName(), readObject());
-            default:
-                // ImmutableList is used by ImmutableOffsetMapTemplate for lookups, hence we use that.
-                final Builder<QName> keys = ImmutableList.builderWithExpectedSize(count);
-                final Object[] values = new Object[count];
-                for (int i = 0; i < count; i++) {
-                    keys.add(readQName());
-                    values[i] = readObject();
-                }
-
-                return NodeIdentifierWithPredicates.of(qname, ImmutableOffsetMapTemplate.ordered(keys.build())
-                    .instantiateWithValues(values));
-        }
-    }
-
-    private Object readObject() throws IOException {
-        byte objectType = input.readByte();
-        return switch (objectType) {
-            case LithiumValue.BITS_TYPE -> readObjSet();
-            case LithiumValue.BOOL_TYPE -> input.readBoolean();
-            case LithiumValue.BYTE_TYPE -> input.readByte();
-            case LithiumValue.INT_TYPE -> input.readInt();
-            case LithiumValue.LONG_TYPE -> input.readLong();
-            case LithiumValue.QNAME_TYPE -> readQName();
-            case LithiumValue.SHORT_TYPE -> input.readShort();
-            case LithiumValue.STRING_TYPE -> input.readUTF();
-            case LithiumValue.STRING_BYTES_TYPE -> readStringBytes();
-            case LithiumValue.BIG_DECIMAL_TYPE -> Decimal64.valueOf(input.readUTF());
-            case LithiumValue.BIG_INTEGER_TYPE -> new BigInteger(input.readUTF());
-            case LithiumValue.BINARY_TYPE -> {
-                byte[] bytes = new byte[input.readInt()];
-                input.readFully(bytes);
-                yield bytes;
-            }
-            case LithiumValue.YANG_IDENTIFIER_TYPE -> readYangInstanceIdentifierInternal();
-            case LithiumValue.EMPTY_TYPE, LithiumValue.NULL_TYPE ->
-            // Leaf nodes no longer allow null values and thus we no longer emit null values. Previously, the "empty"
-            // yang type was represented as null so we translate an incoming null value to Empty. It was possible for
-            // a BI user to set a string leaf to null and we're rolling the dice here but the chances for that are
-            // very low. We'd have to know the yang type but, even if we did, we can't let a null value pass upstream
-            // so we'd have to drop the leaf which might cause other issues.
-                Empty.value();
-            default -> null;
-        };
-    }
-
-    private String readStringBytes() throws IOException {
-        byte[] bytes = new byte[input.readInt()];
-        input.readFully(bytes);
-        return new String(bytes, StandardCharsets.UTF_8);
-    }
-
-    @Override
-    public final YangInstanceIdentifier readYangInstanceIdentifier() throws IOException {
-        return readYangInstanceIdentifierInternal();
-    }
-
-    private @NonNull YangInstanceIdentifier readYangInstanceIdentifierInternal() throws IOException {
-        int size = input.readInt();
-        final Builder<PathArgument> pathArguments = ImmutableList.builderWithExpectedSize(size);
-        for (int i = 0; i < size; i++) {
-            pathArguments.add(readPathArgument());
-        }
-        return YangInstanceIdentifier.of(pathArguments.build());
-    }
-
-    private Set<String> readObjSet() throws IOException {
-        int count = input.readInt();
-        Set<String> children = new HashSet<>(count);
-        for (int i = 0; i < count; i++) {
-            children.add(readCodedString());
-        }
-        return children;
-    }
-
-    @Override
-    @Deprecated(since = "11.0.0", forRemoval = true)
-    public final Either<PathArgument, LegacyPathArgument> readLegacyPathArgument() throws IOException {
-        // read Type
-        int type = input.readByte();
-        return switch (type) {
-            case LithiumPathArgument.AUGMENTATION_IDENTIFIER -> Either.ofSecond(readAugmentationIdentifier());
-            case LithiumPathArgument.NODE_IDENTIFIER -> Either.ofFirst(readNodeIdentifier());
-            case LithiumPathArgument.NODE_IDENTIFIER_WITH_PREDICATES ->
-                Either.ofFirst(readNormalizedNodeWithPredicates());
-            case LithiumPathArgument.NODE_IDENTIFIER_WITH_VALUE ->
-                Either.ofFirst(new NodeWithValue<>(readQName(), readObject()));
-            default -> throw new InvalidNormalizedNodeStreamException("Unexpected PathArgument type " + type);
-        };
-    }
-}
diff --git a/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/AbstractMagnesiumDataInput.java b/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/AbstractMagnesiumDataInput.java
deleted file mode 100644 (file)
index bc3734b..0000000
+++ /dev/null
@@ -1,810 +0,0 @@
-/*
- * Copyright (c) 2019 PANTHEON.tech, s.r.o. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.yangtools.yang.data.codec.binfmt;
-
-import static com.google.common.base.Verify.verifyNotNull;
-import static java.util.Objects.requireNonNull;
-import static org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter.UNKNOWN_SIZE;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableList.Builder;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.util.concurrent.UncheckedExecutionException;
-import java.io.DataInput;
-import java.io.IOException;
-import java.io.StringReader;
-import java.math.BigInteger;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.ExecutionException;
-import javax.xml.transform.dom.DOMSource;
-import org.eclipse.jdt.annotation.NonNull;
-import org.opendaylight.yangtools.concepts.Either;
-import org.opendaylight.yangtools.util.xml.UntrustedXML;
-import org.opendaylight.yangtools.yang.common.Decimal64;
-import org.opendaylight.yangtools.yang.common.Empty;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.common.QNameModule;
-import org.opendaylight.yangtools.yang.common.Uint16;
-import org.opendaylight.yangtools.yang.common.Uint32;
-import org.opendaylight.yangtools.yang.common.Uint64;
-import org.opendaylight.yangtools.yang.common.Uint8;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
-import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
-
-/**
- * Abstract base class for NormalizedNodeDataInput based on {@link MagnesiumNode}, {@link MagnesiumPathArgument} and
- * {@link MagnesiumValue}.
- */
-abstract class AbstractMagnesiumDataInput extends AbstractLegacyDataInput {
-    private static final Logger LOG = LoggerFactory.getLogger(AbstractMagnesiumDataInput.class);
-
-    // Known singleton objects
-    private static final @NonNull Byte INT8_0 = 0;
-    private static final @NonNull Short INT16_0 = 0;
-    private static final @NonNull Integer INT32_0 = 0;
-    private static final @NonNull Long INT64_0 = 0L;
-    private static final byte @NonNull[] BINARY_0 = new byte[0];
-    private static final @NonNull LegacyAugmentationIdentifier EMPTY_AID =
-        new LegacyAugmentationIdentifier(ImmutableSet.of());
-
-    private final List<LegacyAugmentationIdentifier> codedAugments = new ArrayList<>();
-    private final List<NodeIdentifier> codedNodeIdentifiers = new ArrayList<>();
-    private final List<QNameModule> codedModules = new ArrayList<>();
-    private final List<String> codedStrings = new ArrayList<>();
-
-    AbstractMagnesiumDataInput(final DataInput input) {
-        super(input);
-    }
-
-    @Override
-    public final void streamNormalizedNode(final NormalizedNodeStreamWriter writer) throws IOException {
-        streamNormalizedNode(requireNonNull(writer), null, input.readByte());
-    }
-
-    private void streamNormalizedNode(final NormalizedNodeStreamWriter writer, final Object parent,
-            final byte nodeHeader) throws IOException {
-        switch (nodeHeader & MagnesiumNode.TYPE_MASK) {
-            case MagnesiumNode.NODE_LEAF:
-                streamLeaf(writer, parent, nodeHeader);
-                break;
-            case MagnesiumNode.NODE_CONTAINER:
-                streamContainer(writer, nodeHeader);
-                break;
-            case MagnesiumNode.NODE_LIST:
-                streamList(writer, nodeHeader);
-                break;
-            case MagnesiumNode.NODE_MAP:
-                streamMap(writer, nodeHeader);
-                break;
-            case MagnesiumNode.NODE_MAP_ORDERED:
-                streamMapOrdered(writer, nodeHeader);
-                break;
-            case MagnesiumNode.NODE_LEAFSET:
-                streamLeafset(writer, nodeHeader);
-                break;
-            case MagnesiumNode.NODE_LEAFSET_ORDERED:
-                streamLeafsetOrdered(writer, nodeHeader);
-                break;
-            case MagnesiumNode.NODE_CHOICE:
-                streamChoice(writer, nodeHeader);
-                break;
-            case MagnesiumNode.NODE_AUGMENTATION:
-                streamAugmentation(writer, nodeHeader);
-                break;
-            case MagnesiumNode.NODE_ANYXML:
-                streamAnyxml(writer, nodeHeader);
-                break;
-            case MagnesiumNode.NODE_LIST_ENTRY:
-                streamListEntry(writer, parent, nodeHeader);
-                break;
-            case MagnesiumNode.NODE_LEAFSET_ENTRY:
-                streamLeafsetEntry(writer, parent, nodeHeader);
-                break;
-            case MagnesiumNode.NODE_MAP_ENTRY:
-                streamMapEntry(writer, parent, nodeHeader);
-                break;
-            default:
-                throw new InvalidNormalizedNodeStreamException("Unexpected node header " + nodeHeader);
-        }
-    }
-
-    private void streamAnyxml(final NormalizedNodeStreamWriter writer, final byte nodeHeader) throws IOException {
-        final NodeIdentifier identifier = decodeNodeIdentifier(nodeHeader);
-        LOG.trace("Streaming anyxml node {}", identifier);
-
-        final DOMSource value = readDOMSource();
-        if (writer.startAnyxmlNode(identifier, DOMSource.class)) {
-            writer.domSourceValue(value);
-            writer.endNode();
-        }
-    }
-
-    private void streamAugmentation(final NormalizedNodeStreamWriter writer, final byte nodeHeader) throws IOException {
-        final var augIdentifier = decodeAugmentationIdentifier(nodeHeader);
-        LOG.trace("Streaming augmentation node {}", augIdentifier);
-        for (byte nodeType = input.readByte(); nodeType != MagnesiumNode.NODE_END; nodeType = input.readByte()) {
-            streamNormalizedNode(writer, augIdentifier, nodeType);
-        }
-    }
-
-    private void streamChoice(final NormalizedNodeStreamWriter writer, final byte nodeHeader) throws IOException {
-        final NodeIdentifier identifier = decodeNodeIdentifier(nodeHeader);
-        LOG.trace("Streaming choice node {}", identifier);
-        writer.startChoiceNode(identifier, UNKNOWN_SIZE);
-        commonStreamContainer(writer, identifier);
-    }
-
-    private void streamContainer(final NormalizedNodeStreamWriter writer, final byte nodeHeader) throws IOException {
-        final NodeIdentifier identifier = decodeNodeIdentifier(nodeHeader);
-        LOG.trace("Streaming container node {}", identifier);
-        writer.startContainerNode(identifier, UNKNOWN_SIZE);
-        commonStreamContainer(writer, identifier);
-    }
-
-    private void streamLeaf(final NormalizedNodeStreamWriter writer, final Object parent, final byte nodeHeader)
-            throws IOException {
-        final NodeIdentifier identifier = decodeNodeIdentifier(nodeHeader);
-        LOG.trace("Streaming leaf node {}", identifier);
-        writer.startLeafNode(identifier);
-
-        final Object value;
-        if ((nodeHeader & MagnesiumNode.PREDICATE_ONE) == MagnesiumNode.PREDICATE_ONE) {
-            if (!(parent instanceof NodeIdentifierWithPredicates nip)) {
-                throw new InvalidNormalizedNodeStreamException("Invalid predicate leaf " + identifier + " in parent "
-                        + parent);
-            }
-
-            value = nip.getValue(identifier.getNodeType());
-            if (value == null) {
-                throw new InvalidNormalizedNodeStreamException("Failed to find predicate leaf " + identifier
-                    + " in parent " + parent);
-            }
-        } else {
-            value = readLeafValue();
-        }
-
-        writer.scalarValue(value);
-        writer.endNode();
-    }
-
-    private void streamLeafset(final NormalizedNodeStreamWriter writer, final byte nodeHeader) throws IOException {
-        final NodeIdentifier identifier = decodeNodeIdentifier(nodeHeader);
-        LOG.trace("Streaming leaf set node {}", identifier);
-        writer.startLeafSet(identifier, UNKNOWN_SIZE);
-        commonStreamContainer(writer, identifier);
-    }
-
-    private void streamLeafsetOrdered(final NormalizedNodeStreamWriter writer, final byte nodeHeader)
-            throws IOException {
-        final NodeIdentifier identifier = decodeNodeIdentifier(nodeHeader);
-        LOG.trace("Streaming ordered leaf set node {}", identifier);
-        writer.startOrderedLeafSet(identifier, UNKNOWN_SIZE);
-
-        commonStreamContainer(writer, identifier);
-    }
-
-    private void streamLeafsetEntry(final NormalizedNodeStreamWriter writer, final Object parent, final byte nodeHeader)
-            throws IOException {
-        final NodeIdentifier nodeId = decodeNodeIdentifier(nodeHeader, parent);
-        final Object value = readLeafValue();
-        final NodeWithValue<Object> leafIdentifier = new NodeWithValue<>(nodeId.getNodeType(), value);
-        LOG.trace("Streaming leaf set entry node {}", leafIdentifier);
-        writer.startLeafSetEntryNode(leafIdentifier);
-        writer.scalarValue(value);
-        writer.endNode();
-    }
-
-    private void streamList(final NormalizedNodeStreamWriter writer, final byte nodeHeader) throws IOException {
-        final NodeIdentifier identifier = decodeNodeIdentifier(nodeHeader);
-        writer.startUnkeyedList(identifier, UNKNOWN_SIZE);
-        commonStreamContainer(writer, identifier);
-    }
-
-    private void streamListEntry(final NormalizedNodeStreamWriter writer, final Object parent, final byte nodeHeader)
-            throws IOException {
-        final NodeIdentifier identifier = decodeNodeIdentifier(nodeHeader, parent);
-        LOG.trace("Streaming unkeyed list item node {}", identifier);
-        writer.startUnkeyedListItem(identifier, UNKNOWN_SIZE);
-        commonStreamContainer(writer, identifier);
-    }
-
-    private void streamMap(final NormalizedNodeStreamWriter writer, final byte nodeHeader) throws IOException {
-        final NodeIdentifier identifier = decodeNodeIdentifier(nodeHeader);
-        LOG.trace("Streaming map node {}", identifier);
-        writer.startMapNode(identifier, UNKNOWN_SIZE);
-        commonStreamContainer(writer, identifier);
-    }
-
-    private void streamMapOrdered(final NormalizedNodeStreamWriter writer, final byte nodeHeader) throws IOException {
-        final NodeIdentifier identifier = decodeNodeIdentifier(nodeHeader);
-        LOG.trace("Streaming ordered map node {}", identifier);
-        writer.startOrderedMapNode(identifier, UNKNOWN_SIZE);
-        commonStreamContainer(writer, identifier);
-    }
-
-    private void streamMapEntry(final NormalizedNodeStreamWriter writer, final Object parent, final byte nodeHeader)
-            throws IOException {
-        final NodeIdentifier nodeId = decodeNodeIdentifier(nodeHeader, parent);
-
-        final int size = switch (mask(nodeHeader, MagnesiumNode.PREDICATE_MASK)) {
-            case MagnesiumNode.PREDICATE_ZERO -> 0;
-            case MagnesiumNode.PREDICATE_ONE -> 1;
-            case MagnesiumNode.PREDICATE_1B -> input.readUnsignedByte();
-            case MagnesiumNode.PREDICATE_4B -> input.readInt();
-            default ->
-                // ISE on purpose: this should never ever happen
-                throw new IllegalStateException("Failed to decode NodeIdentifierWithPredicates size from header "
-                    + nodeHeader);
-        };
-        final NodeIdentifierWithPredicates identifier = readNodeIdentifierWithPredicates(nodeId.getNodeType(), size);
-        LOG.trace("Streaming map entry node {}", identifier);
-        writer.startMapEntryNode(identifier, UNKNOWN_SIZE);
-        commonStreamContainer(writer, identifier);
-    }
-
-    private void commonStreamContainer(final NormalizedNodeStreamWriter writer, final PathArgument parent)
-            throws IOException {
-        for (byte nodeType = input.readByte(); nodeType != MagnesiumNode.NODE_END; nodeType = input.readByte()) {
-            streamNormalizedNode(writer, parent, nodeType);
-        }
-        writer.endNode();
-    }
-
-    private @NonNull NodeIdentifier decodeNodeIdentifier() throws IOException {
-        final QNameModule module = decodeQNameModule();
-        final String localName = readRefString();
-        final NodeIdentifier nodeId;
-        try {
-            nodeId = QNameFactory.getNodeIdentifier(module, localName);
-        } catch (ExecutionException e) {
-            throw new InvalidNormalizedNodeStreamException("Illegal QName module=" + module + " localName="
-                    + localName, e);
-        }
-
-        codedNodeIdentifiers.add(nodeId);
-        return nodeId;
-    }
-
-    private NodeIdentifier decodeNodeIdentifier(final byte nodeHeader) throws IOException {
-        return decodeNodeIdentifier(nodeHeader, null);
-    }
-
-    private NodeIdentifier decodeNodeIdentifier(final byte nodeHeader, final Object parent) throws IOException {
-        final int index;
-        switch (nodeHeader & MagnesiumNode.ADDR_MASK) {
-            case MagnesiumNode.ADDR_DEFINE:
-                return readNodeIdentifier();
-            case MagnesiumNode.ADDR_LOOKUP_1B:
-                index = input.readUnsignedByte();
-                break;
-            case MagnesiumNode.ADDR_LOOKUP_4B:
-                index = input.readInt();
-                break;
-            case MagnesiumNode.ADDR_PARENT:
-                if (parent instanceof NodeIdentifier nid) {
-                    return nid;
-                }
-                throw new InvalidNormalizedNodeStreamException("Invalid node identifier reference to parent " + parent);
-            default:
-                throw new InvalidNormalizedNodeStreamException("Unexpected node identifier addressing in header "
-                        + nodeHeader);
-        }
-
-        try {
-            return codedNodeIdentifiers.get(index);
-        } catch (IndexOutOfBoundsException e) {
-            throw new InvalidNormalizedNodeStreamException("Invalid QName reference " + index, e);
-        }
-    }
-
-    private LegacyAugmentationIdentifier decodeAugmentationIdentifier(final byte nodeHeader) throws IOException {
-        final int index;
-        switch (nodeHeader & MagnesiumNode.ADDR_MASK) {
-            case MagnesiumNode.ADDR_DEFINE:
-                return readAugmentationIdentifier();
-            case MagnesiumNode.ADDR_LOOKUP_1B:
-                index = input.readUnsignedByte();
-                break;
-            case MagnesiumNode.ADDR_LOOKUP_4B:
-                index = input.readInt();
-                break;
-            default:
-                throw new InvalidNormalizedNodeStreamException(
-                    "Unexpected augmentation identifier addressing in header " + nodeHeader);
-        }
-
-        try {
-            return codedAugments.get(index);
-        } catch (IndexOutOfBoundsException e) {
-            throw new InvalidNormalizedNodeStreamException("Invalid augmentation identifier reference " + index, e);
-        }
-    }
-
-    @Override
-    public final YangInstanceIdentifier readYangInstanceIdentifier() throws IOException {
-        final byte type = input.readByte();
-        if (type == MagnesiumValue.YIID) {
-            return readYangInstanceIdentifier(input.readInt());
-        } else if (type >= MagnesiumValue.YIID_0) {
-            // Note 'byte' is range limited, so it is always '&& type <= MagnesiumValue.YIID_31'
-            return readYangInstanceIdentifier(type - MagnesiumValue.YIID_0);
-        } else {
-            throw new InvalidNormalizedNodeStreamException("Unexpected YangInstanceIdentifier type " + type);
-        }
-    }
-
-    private @NonNull YangInstanceIdentifier readYangInstanceIdentifier(final int size) throws IOException {
-        if (size > 0) {
-            final Builder<PathArgument> builder = ImmutableList.builderWithExpectedSize(size);
-            for (int i = 0; i < size; ++i) {
-                builder.add(readPathArgument());
-            }
-            return YangInstanceIdentifier.of(builder.build());
-        } else if (size == 0) {
-            return YangInstanceIdentifier.of();
-        } else {
-            throw new InvalidNormalizedNodeStreamException("Invalid YangInstanceIdentifier size " + size);
-        }
-    }
-
-    @Override
-    public final QName readQName() throws IOException {
-        final byte type = input.readByte();
-        return switch (type) {
-            case MagnesiumValue.QNAME -> decodeQName();
-            case MagnesiumValue.QNAME_REF_1B -> decodeQNameRef1();
-            case MagnesiumValue.QNAME_REF_2B -> decodeQNameRef2();
-            case MagnesiumValue.QNAME_REF_4B -> decodeQNameRef4();
-            default -> throw new InvalidNormalizedNodeStreamException("Unexpected QName type " + type);
-        };
-    }
-
-    @Override
-    @Deprecated(since = "11.0.0", forRemoval = true)
-    public final Either<PathArgument, LegacyPathArgument> readLegacyPathArgument() throws IOException {
-        final byte header = input.readByte();
-        return switch (header & MagnesiumPathArgument.TYPE_MASK) {
-            case MagnesiumPathArgument.AUGMENTATION_IDENTIFIER -> Either.ofSecond(readAugmentationIdentifier(header));
-            case MagnesiumPathArgument.NODE_IDENTIFIER -> {
-                verifyPathIdentifierOnly(header);
-                yield Either.ofFirst(readNodeIdentifier(header));
-            }
-            case MagnesiumPathArgument.NODE_IDENTIFIER_WITH_PREDICATES ->
-                Either.ofFirst(readNodeIdentifierWithPredicates(header));
-            case MagnesiumPathArgument.NODE_WITH_VALUE -> {
-                verifyPathIdentifierOnly(header);
-                yield Either.ofFirst(readNodeWithValue(header));
-            }
-            case MagnesiumPathArgument.MOUNTPOINT_IDENTIFIER -> {
-                verifyPathIdentifierOnly(header);
-                yield Either.ofSecond(new LegacyMountPointIdentifier(readNodeIdentifier(header).getNodeType()));
-            }
-            default -> throw new InvalidNormalizedNodeStreamException("Unexpected PathArgument header " + header);
-        };
-    }
-
-    private @NonNull LegacyAugmentationIdentifier readAugmentationIdentifier() throws IOException {
-        final var result = readAugmentationIdentifier(input.readInt());
-        codedAugments.add(result);
-        return result;
-    }
-
-    private @NonNull LegacyAugmentationIdentifier readAugmentationIdentifier(final byte header) throws IOException {
-        final byte count = mask(header, MagnesiumPathArgument.AID_COUNT_MASK);
-        return switch (count) {
-            case MagnesiumPathArgument.AID_COUNT_1B -> readAugmentationIdentifier(input.readUnsignedByte());
-            case MagnesiumPathArgument.AID_COUNT_2B -> readAugmentationIdentifier(input.readUnsignedShort());
-            case MagnesiumPathArgument.AID_COUNT_4B -> readAugmentationIdentifier(input.readInt());
-            default -> readAugmentationIdentifier(rshift(count, MagnesiumPathArgument.AID_COUNT_SHIFT));
-        };
-    }
-
-    private @NonNull LegacyAugmentationIdentifier readAugmentationIdentifier(final int size) throws IOException {
-        if (size > 0) {
-            final var qnames = ImmutableSet.<QName>builderWithExpectedSize(size);
-            for (int i = 0; i < size; ++i) {
-                qnames.add(readQName());
-            }
-            return new LegacyAugmentationIdentifier(qnames.build());
-        } else if (size == 0) {
-            return EMPTY_AID;
-        } else {
-            throw new InvalidNormalizedNodeStreamException("Invalid augmentation identifier size " + size);
-        }
-    }
-
-    private @NonNull NodeIdentifier readNodeIdentifier() throws IOException {
-        return decodeNodeIdentifier();
-    }
-
-    private @NonNull NodeIdentifier readNodeIdentifier(final byte header) throws IOException {
-        return switch (header & MagnesiumPathArgument.QNAME_MASK) {
-            case MagnesiumPathArgument.QNAME_DEF -> decodeNodeIdentifier();
-            case MagnesiumPathArgument.QNAME_REF_1B -> decodeNodeIdentifierRef1();
-            case MagnesiumPathArgument.QNAME_REF_2B -> decodeNodeIdentifierRef2();
-            case MagnesiumPathArgument.QNAME_REF_4B -> decodeNodeIdentifierRef4();
-            default -> throw new InvalidNormalizedNodeStreamException("Invalid QName coding in " + header);
-        };
-    }
-
-    private @NonNull  NodeIdentifierWithPredicates readNodeIdentifierWithPredicates(final byte header)
-            throws IOException {
-        final QName qname = readNodeIdentifier(header).getNodeType();
-        return switch (mask(header, MagnesiumPathArgument.SIZE_MASK)) {
-            case MagnesiumPathArgument.SIZE_1B -> readNodeIdentifierWithPredicates(qname, input.readUnsignedByte());
-            case MagnesiumPathArgument.SIZE_2B -> readNodeIdentifierWithPredicates(qname, input.readUnsignedShort());
-            case MagnesiumPathArgument.SIZE_4B -> readNodeIdentifierWithPredicates(qname, input.readInt());
-            default -> readNodeIdentifierWithPredicates(qname, rshift(header, MagnesiumPathArgument.SIZE_SHIFT));
-        };
-    }
-
-    private @NonNull NodeIdentifierWithPredicates readNodeIdentifierWithPredicates(final QName qname, final int size)
-            throws IOException {
-        if (size == 1) {
-            return NodeIdentifierWithPredicates.of(qname, readQName(), readLeafValue());
-        } else if (size > 1) {
-            final ImmutableMap.Builder<QName, Object> builder = ImmutableMap.builderWithExpectedSize(size);
-            for (int i = 0; i < size; ++i) {
-                builder.put(readQName(), readLeafValue());
-            }
-            return NodeIdentifierWithPredicates.of(qname, builder.build());
-        } else if (size == 0) {
-            return NodeIdentifierWithPredicates.of(qname);
-        } else {
-            throw new InvalidNormalizedNodeStreamException("Invalid predicate count " + size);
-        }
-    }
-
-    private @NonNull NodeWithValue<?> readNodeWithValue(final byte header) throws IOException {
-        final QName qname = readNodeIdentifier(header).getNodeType();
-        return new NodeWithValue<>(qname, readLeafValue());
-    }
-
-    private static void verifyPathIdentifierOnly(final byte header) throws InvalidNormalizedNodeStreamException {
-        if (mask(header, MagnesiumPathArgument.SIZE_MASK) != 0) {
-            throw new InvalidNormalizedNodeStreamException("Invalid path argument header " + header);
-        }
-    }
-
-    private @NonNull NodeIdentifier decodeNodeIdentifierRef1() throws IOException {
-        return lookupNodeIdentifier(input.readUnsignedByte());
-    }
-
-    private @NonNull NodeIdentifier decodeNodeIdentifierRef2() throws IOException {
-        return lookupNodeIdentifier(input.readUnsignedShort() + 256);
-    }
-
-    private @NonNull NodeIdentifier decodeNodeIdentifierRef4() throws IOException {
-        return lookupNodeIdentifier(input.readInt());
-    }
-
-    private @NonNull QName decodeQName() throws IOException {
-        return decodeNodeIdentifier().getNodeType();
-    }
-
-    private @NonNull QName decodeQNameRef1() throws IOException {
-        return lookupQName(input.readUnsignedByte());
-    }
-
-    private @NonNull QName decodeQNameRef2() throws IOException {
-        return lookupQName(input.readUnsignedShort() + 256);
-    }
-
-    private @NonNull QName decodeQNameRef4() throws IOException {
-        return lookupQName(input.readInt());
-    }
-
-    private @NonNull QNameModule decodeQNameModule() throws IOException {
-        final byte type = input.readByte();
-        final int index;
-        switch (type) {
-            case MagnesiumValue.MODREF_1B:
-                index = input.readUnsignedByte();
-                break;
-            case MagnesiumValue.MODREF_2B:
-                index = input.readUnsignedShort() + 256;
-                break;
-            case MagnesiumValue.MODREF_4B:
-                index = input.readInt();
-                break;
-            default:
-                return decodeQNameModuleDef(type);
-        }
-
-        try {
-            return codedModules.get(index);
-        } catch (IndexOutOfBoundsException e) {
-            throw new InvalidNormalizedNodeStreamException("Invalid QNameModule reference " + index, e);
-        }
-    }
-
-    // QNameModule definition, i.e. two encoded strings
-    private @NonNull QNameModule decodeQNameModuleDef(final byte type) throws IOException {
-        final String namespace = readRefString(type);
-
-        final byte refType = input.readByte();
-        final String revision = refType == MagnesiumValue.STRING_EMPTY ? null : readRefString(refType);
-        final QNameModule module;
-        try {
-            module = QNameFactory.createModule(namespace, revision);
-        } catch (UncheckedExecutionException e) {
-            throw new InvalidNormalizedNodeStreamException("Illegal QNameModule ns=" + namespace + " rev=" + revision,
-                e);
-        }
-
-        codedModules.add(module);
-        return module;
-    }
-
-    private @NonNull String readRefString() throws IOException {
-        return readRefString(input.readByte());
-    }
-
-    private @NonNull String readRefString(final byte type) throws IOException {
-        final String str;
-        switch (type) {
-            case MagnesiumValue.STRING_REF_1B:
-                return lookupString(input.readUnsignedByte());
-            case MagnesiumValue.STRING_REF_2B:
-                return lookupString(input.readUnsignedShort() + 256);
-            case MagnesiumValue.STRING_REF_4B:
-                return lookupString(input.readInt());
-            case MagnesiumValue.STRING_EMPTY:
-                return "";
-            case MagnesiumValue.STRING_2B:
-                str = readString2();
-                break;
-            case MagnesiumValue.STRING_4B:
-                str = readString4();
-                break;
-            case MagnesiumValue.STRING_CHARS:
-                str = readCharsString();
-                break;
-            case MagnesiumValue.STRING_UTF:
-                str = input.readUTF();
-                break;
-            default:
-                throw new InvalidNormalizedNodeStreamException("Unexpected String type " + type);
-        }
-
-        // TODO: consider interning Strings -- that would help with bits, but otherwise it's probably not worth it
-        codedStrings.add(verifyNotNull(str));
-        return str;
-    }
-
-    private @NonNull String readString() throws IOException {
-        final byte type = input.readByte();
-        return switch (type) {
-            case MagnesiumValue.STRING_EMPTY -> "";
-            case MagnesiumValue.STRING_UTF -> input.readUTF();
-            case MagnesiumValue.STRING_2B -> readString2();
-            case MagnesiumValue.STRING_4B -> readString4();
-            case MagnesiumValue.STRING_CHARS -> readCharsString();
-            default -> throw new InvalidNormalizedNodeStreamException("Unexpected String type " + type);
-        };
-    }
-
-    private @NonNull String readString2() throws IOException {
-        return readByteString(input.readUnsignedShort());
-    }
-
-    private @NonNull String readString4() throws IOException {
-        return readByteString(input.readInt());
-    }
-
-    private @NonNull String readByteString(final int size) throws IOException {
-        if (size > 0) {
-            final byte[] bytes = new byte[size];
-            input.readFully(bytes);
-            return new String(bytes, StandardCharsets.UTF_8);
-        } else if (size == 0) {
-            return "";
-        } else {
-            throw new InvalidNormalizedNodeStreamException("Invalid String bytes length " + size);
-        }
-    }
-
-    private @NonNull String readCharsString() throws IOException {
-        final int size = input.readInt();
-        if (size > 0) {
-            final char[] chars = new char[size];
-            for (int i = 0; i < size; ++i) {
-                chars[i] = input.readChar();
-            }
-            return String.valueOf(chars);
-        } else if (size == 0) {
-            return "";
-        } else {
-            throw new InvalidNormalizedNodeStreamException("Invalid String chars length " + size);
-        }
-    }
-
-    private @NonNull NodeIdentifier lookupNodeIdentifier(final int index) throws InvalidNormalizedNodeStreamException {
-        try {
-            return codedNodeIdentifiers.get(index);
-        } catch (IndexOutOfBoundsException e) {
-            throw new InvalidNormalizedNodeStreamException("Invalid QName reference " + index, e);
-        }
-    }
-
-    private @NonNull QName lookupQName(final int index) throws InvalidNormalizedNodeStreamException {
-        return lookupNodeIdentifier(index).getNodeType();
-    }
-
-    private @NonNull String lookupString(final int index) throws InvalidNormalizedNodeStreamException {
-        try {
-            return codedStrings.get(index);
-        } catch (IndexOutOfBoundsException e) {
-            throw new InvalidNormalizedNodeStreamException("Invalid String reference " + index, e);
-        }
-    }
-
-    private @NonNull DOMSource readDOMSource() throws IOException {
-        final String str = readString();
-        try {
-            return new DOMSource(UntrustedXML.newDocumentBuilder().parse(new InputSource(new StringReader(str)))
-                .getDocumentElement());
-        } catch (SAXException e) {
-            throw new IOException("Error parsing XML: " + str, e);
-        }
-    }
-
-    private @NonNull Object readLeafValue() throws IOException {
-        final byte type = input.readByte();
-        switch (type) {
-            case MagnesiumValue.BOOLEAN_FALSE:
-                return Boolean.FALSE;
-            case MagnesiumValue.BOOLEAN_TRUE:
-                return Boolean.TRUE;
-            case MagnesiumValue.EMPTY:
-                return Empty.value();
-            case MagnesiumValue.INT8:
-                return input.readByte();
-            case MagnesiumValue.INT8_0:
-                return INT8_0;
-            case MagnesiumValue.INT16:
-                return input.readShort();
-            case MagnesiumValue.INT16_0:
-                return INT16_0;
-            case MagnesiumValue.INT32:
-                return input.readInt();
-            case MagnesiumValue.INT32_0:
-                return INT32_0;
-            case MagnesiumValue.INT32_2B:
-                return input.readShort() & 0xFFFF;
-            case MagnesiumValue.INT64:
-                return input.readLong();
-            case MagnesiumValue.INT64_0:
-                return INT64_0;
-            case MagnesiumValue.INT64_4B:
-                return input.readInt() & 0xFFFFFFFFL;
-            case MagnesiumValue.UINT8:
-                return Uint8.fromByteBits(input.readByte());
-            case MagnesiumValue.UINT8_0:
-                return Uint8.ZERO;
-            case MagnesiumValue.UINT16:
-                return Uint16.fromShortBits(input.readShort());
-            case MagnesiumValue.UINT16_0:
-                return Uint16.ZERO;
-            case MagnesiumValue.UINT32:
-                return Uint32.fromIntBits(input.readInt());
-            case MagnesiumValue.UINT32_0:
-                return Uint32.ZERO;
-            case MagnesiumValue.UINT32_2B:
-                return Uint32.fromIntBits(input.readShort() & 0xFFFF);
-            case MagnesiumValue.UINT64:
-                return Uint64.fromLongBits(input.readLong());
-            case MagnesiumValue.UINT64_0:
-                return Uint64.ZERO;
-            case MagnesiumValue.UINT64_4B:
-                return Uint64.fromLongBits(input.readInt() & 0xFFFFFFFFL);
-            case MagnesiumValue.BIGDECIMAL:
-                // FIXME: use string -> BigDecimal cache
-                return Decimal64.valueOf(input.readUTF());
-            case MagnesiumValue.BIGINTEGER:
-                return readBigInteger();
-            case MagnesiumValue.STRING_EMPTY:
-                return "";
-            case MagnesiumValue.STRING_UTF:
-                return input.readUTF();
-            case MagnesiumValue.STRING_2B:
-                return readString2();
-            case MagnesiumValue.STRING_4B:
-                return readString4();
-            case MagnesiumValue.STRING_CHARS:
-                return readCharsString();
-            case MagnesiumValue.BINARY_0:
-                return BINARY_0;
-            case MagnesiumValue.BINARY_1B:
-                return readBinary(128 + input.readUnsignedByte());
-            case MagnesiumValue.BINARY_2B:
-                return readBinary(384 + input.readUnsignedShort());
-            case MagnesiumValue.BINARY_4B:
-                return readBinary(input.readInt());
-            case MagnesiumValue.YIID_0:
-                return YangInstanceIdentifier.of();
-            case MagnesiumValue.YIID:
-                return readYangInstanceIdentifier(input.readInt());
-            case MagnesiumValue.QNAME:
-                return decodeQName();
-            case MagnesiumValue.QNAME_REF_1B:
-                return decodeQNameRef1();
-            case MagnesiumValue.QNAME_REF_2B:
-                return decodeQNameRef2();
-            case MagnesiumValue.QNAME_REF_4B:
-                return decodeQNameRef4();
-            case MagnesiumValue.BITS_0:
-                return ImmutableSet.of();
-            case MagnesiumValue.BITS_1B:
-                return readBits(input.readUnsignedByte() + 29);
-            case MagnesiumValue.BITS_2B:
-                return readBits(input.readUnsignedShort() + 285);
-            case MagnesiumValue.BITS_4B:
-                return readBits(input.readInt());
-
-            default:
-                if (type > MagnesiumValue.BINARY_0 && type <= MagnesiumValue.BINARY_127) {
-                    return readBinary(type - MagnesiumValue.BINARY_0);
-                } else if (type > MagnesiumValue.BITS_0 && type < MagnesiumValue.BITS_1B) {
-                    return readBits(type - MagnesiumValue.BITS_0);
-                } else if (type > MagnesiumValue.YIID_0) {
-                    // Note 'byte' is range limited, so it is always '&& type <= MagnesiumValue.YIID_31'
-                    return readYangInstanceIdentifier(type - MagnesiumValue.YIID_0);
-                } else {
-                    throw new InvalidNormalizedNodeStreamException("Invalid value type " + type);
-                }
-        }
-    }
-
-    abstract @NonNull BigInteger readBigInteger() throws IOException;
-
-    private byte @NonNull [] readBinary(final int size) throws IOException {
-        if (size > 0) {
-            final byte[] ret = new byte[size];
-            input.readFully(ret);
-            return ret;
-        } else if (size == 0) {
-            return BINARY_0;
-        } else {
-            throw new InvalidNormalizedNodeStreamException("Invalid binary length " + size);
-        }
-    }
-
-    private @NonNull ImmutableSet<String> readBits(final int size) throws IOException {
-        if (size > 0) {
-            final ImmutableSet.Builder<String> builder = ImmutableSet.builder();
-            for (int i = 0; i < size; ++i) {
-                builder.add(readRefString());
-            }
-            return builder.build();
-        } else if (size == 0) {
-            return ImmutableSet.of();
-        } else {
-            throw new InvalidNormalizedNodeStreamException("Invalid bits length " + size);
-        }
-    }
-
-    private static byte mask(final byte header, final byte mask) {
-        return (byte) (header & mask);
-    }
-
-    private static int rshift(final byte header, final byte shift) {
-        return (header & 0xFF) >>> shift;
-    }
-}
diff --git a/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/LithiumNode.java b/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/LithiumNode.java
deleted file mode 100644 (file)
index f43a8c1..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (c) 2014, 2015 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.yangtools.yang.data.codec.binfmt;
-
-/**
- * Stream constants identifying individual node types.
- */
-final class LithiumNode {
-    static final byte LEAF_NODE = 1;
-    static final byte LEAF_SET = 2;
-    static final byte LEAF_SET_ENTRY_NODE = 3;
-    static final byte CONTAINER_NODE = 4;
-    static final byte UNKEYED_LIST = 5;
-    static final byte UNKEYED_LIST_ITEM = 6;
-    static final byte MAP_NODE = 7;
-    static final byte MAP_ENTRY_NODE = 8;
-    static final byte ORDERED_MAP_NODE = 9;
-    static final byte CHOICE_NODE = 10;
-    static final byte AUGMENTATION_NODE = 11;
-    static final byte ANY_XML_NODE = 12;
-    static final byte END_NODE = 13;
-    static final byte ORDERED_LEAF_SET = 14;
-    // Note: never emitted as of yangtools-7.0.0
-    @Deprecated
-    static final byte YANG_MODELED_ANY_XML_NODE = 15;
-
-    private LithiumNode() {
-        // Utility class
-    }
-}
diff --git a/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/LithiumNormalizedNodeInputStreamReader.java b/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/LithiumNormalizedNodeInputStreamReader.java
deleted file mode 100755 (executable)
index 8734b5d..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2014, 2015 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.yangtools.yang.data.codec.binfmt;
-
-import com.google.common.base.Strings;
-import java.io.DataInput;
-import java.io.IOException;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
-
-/**
- * Lithium (or Oxygen really) specialization of AbstractLithiumDataInput.
- */
-final class LithiumNormalizedNodeInputStreamReader extends AbstractLithiumDataInput {
-    LithiumNormalizedNodeInputStreamReader(final DataInput input) {
-        super(input);
-    }
-
-    @Override
-    @Deprecated(since = "11.0.0", forRemoval = true)
-    public NormalizedNodeStreamVersion getVersion() {
-        return NormalizedNodeStreamVersion.LITHIUM;
-    }
-
-    @Override
-    public QName readQName() throws IOException {
-        // Read in the same sequence of writing
-        String localName = readCodedString();
-        String namespace = readCodedString();
-        String revision = Strings.emptyToNull(readCodedString());
-
-        return QNameFactory.create(localName, namespace, revision);
-    }
-
-    @Override
-    LegacyAugmentationIdentifier readAugmentationIdentifier() throws IOException {
-        return defaultReadAugmentationIdentifier();
-    }
-
-    @Override
-    NodeIdentifier readNodeIdentifier() throws IOException {
-        return new NodeIdentifier(readQName());
-    }
-}
diff --git a/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/LithiumPathArgument.java b/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/LithiumPathArgument.java
deleted file mode 100644 (file)
index 63a2a10..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.yangtools.yang.data.codec.binfmt;
-
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
-
-final class LithiumPathArgument {
-    static final byte AUGMENTATION_IDENTIFIER = 1;
-    static final byte NODE_IDENTIFIER = 2;
-    static final byte NODE_IDENTIFIER_WITH_VALUE = 3;
-    static final byte NODE_IDENTIFIER_WITH_PREDICATES = 4;
-
-    private LithiumPathArgument() {
-        // Utility class
-    }
-
-    static byte getSerializablePathArgumentType(final PathArgument pathArgument) {
-        if (pathArgument instanceof NodeIdentifier) {
-            return NODE_IDENTIFIER;
-        } else if (pathArgument instanceof NodeIdentifierWithPredicates) {
-            return NODE_IDENTIFIER_WITH_PREDICATES;
-        } else if (pathArgument instanceof NodeWithValue) {
-            return NODE_IDENTIFIER_WITH_VALUE;
-        } else {
-            throw new IllegalArgumentException("Unknown type of PathArgument = " + pathArgument);
-        }
-    }
-}
diff --git a/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/LithiumTokens.java b/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/LithiumTokens.java
deleted file mode 100644 (file)
index 25bcfbe..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.yangtools.yang.data.codec.binfmt;
-
-/**
- * Tokens related to Lithium/NeonSR2 encoding.
- */
-final class LithiumTokens {
-    /**
-     * The value is a reference to a previously-defined entity, typically through {@link #IS_STRING_VALUE}.
-     */
-    static final byte IS_CODE_VALUE = 1;
-    /**
-     * The value is a String, which needs to be kept memoized for the purposes for being referenced by
-     * {@link #IS_CODE_VALUE}.
-     */
-    static final byte IS_STRING_VALUE = 2;
-    /**
-     * The value is an explicit null.
-     */
-    static final byte IS_NULL_VALUE = 3;
-
-    private LithiumTokens() {
-
-    }
-}
diff --git a/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/LithiumValue.java b/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/LithiumValue.java
deleted file mode 100644 (file)
index c717b47..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.yangtools.yang.data.codec.binfmt;
-
-final class LithiumValue {
-    // The String length threshold beyond which a String should be encoded as bytes
-    static final int STRING_BYTES_LENGTH_THRESHOLD = Short.MAX_VALUE / 4;
-
-    static final byte SHORT_TYPE = 1;
-    static final byte BYTE_TYPE = 2;
-    static final byte INT_TYPE = 3;
-    static final byte LONG_TYPE = 4;
-    static final byte BOOL_TYPE = 5;
-    static final byte QNAME_TYPE = 6;
-    static final byte BITS_TYPE = 7;
-    static final byte YANG_IDENTIFIER_TYPE = 8;
-    static final byte STRING_TYPE = 9;
-    static final byte BIG_INTEGER_TYPE = 10;
-    static final byte BIG_DECIMAL_TYPE = 11;
-    static final byte BINARY_TYPE = 12;
-    // Leaf nodes no longer allow null values. The "empty" type is now represented as
-    // org.opendaylight.yangtools.yang.common.Empty. This is kept for backwards compatibility.
-    @Deprecated
-    static final byte NULL_TYPE = 13;
-    static final byte STRING_BYTES_TYPE = 14;
-    static final byte EMPTY_TYPE = 15;
-
-    private LithiumValue() {
-        // Utility class
-    }
-}
index 08adc4630a4139983f69c2f0e9ff01e321073310..41f5a885a31477b68cfe274636e5bd2711d7de02 100644 (file)
@@ -7,11 +7,65 @@
  */
 package org.opendaylight.yangtools.yang.data.codec.binfmt;
 
+import static com.google.common.base.Verify.verifyNotNull;
+import static java.util.Objects.requireNonNull;
+import static org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter.UNKNOWN_SIZE;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableList.Builder;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.util.concurrent.UncheckedExecutionException;
 import java.io.DataInput;
 import java.io.IOException;
-import java.math.BigInteger;
+import java.io.StringReader;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+import javax.xml.transform.dom.DOMSource;
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.yangtools.concepts.Either;
+import org.opendaylight.yangtools.util.xml.UntrustedXML;
+import org.opendaylight.yangtools.yang.common.Decimal64;
+import org.opendaylight.yangtools.yang.common.Empty;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.common.Uint16;
+import org.opendaylight.yangtools.yang.common.Uint32;
+import org.opendaylight.yangtools.yang.common.Uint64;
+import org.opendaylight.yangtools.yang.common.Uint8;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+/**
+ * NormalizedNodeDataInput based on {@link MagnesiumNode}, {@link MagnesiumPathArgument} and {@link MagnesiumValue}.
+ */
+final class MagnesiumDataInput extends AbstractLegacyDataInput {
+    private static final Logger LOG = LoggerFactory.getLogger(MagnesiumDataInput.class);
+
+    // Known singleton objects
+    private static final @NonNull Byte INT8_0 = 0;
+    private static final @NonNull Short INT16_0 = 0;
+    private static final @NonNull Integer INT32_0 = 0;
+    private static final @NonNull Long INT64_0 = 0L;
+    private static final byte @NonNull[] BINARY_0 = new byte[0];
+    private static final @NonNull LegacyAugmentationIdentifier EMPTY_AID =
+        new LegacyAugmentationIdentifier(ImmutableSet.of());
+
+    private final List<LegacyAugmentationIdentifier> codedAugments = new ArrayList<>();
+    private final List<NodeIdentifier> codedNodeIdentifiers = new ArrayList<>();
+    private final List<QNameModule> codedModules = new ArrayList<>();
+    private final List<String> codedStrings = new ArrayList<>();
 
-final class MagnesiumDataInput extends AbstractMagnesiumDataInput {
     MagnesiumDataInput(final DataInput input) {
         super(input);
     }
@@ -22,7 +76,736 @@ final class MagnesiumDataInput extends AbstractMagnesiumDataInput {
     }
 
     @Override
-    BigInteger readBigInteger() throws IOException {
-        throw new InvalidNormalizedNodeStreamException("BigInteger coding is not supported");
+    public void streamNormalizedNode(final NormalizedNodeStreamWriter writer) throws IOException {
+        streamNormalizedNode(requireNonNull(writer), null, input.readByte());
+    }
+
+    private void streamNormalizedNode(final NormalizedNodeStreamWriter writer, final Object parent,
+            final byte nodeHeader) throws IOException {
+        switch (nodeHeader & MagnesiumNode.TYPE_MASK) {
+            case MagnesiumNode.NODE_LEAF:
+                streamLeaf(writer, parent, nodeHeader);
+                break;
+            case MagnesiumNode.NODE_CONTAINER:
+                streamContainer(writer, nodeHeader);
+                break;
+            case MagnesiumNode.NODE_LIST:
+                streamList(writer, nodeHeader);
+                break;
+            case MagnesiumNode.NODE_MAP:
+                streamMap(writer, nodeHeader);
+                break;
+            case MagnesiumNode.NODE_MAP_ORDERED:
+                streamMapOrdered(writer, nodeHeader);
+                break;
+            case MagnesiumNode.NODE_LEAFSET:
+                streamLeafset(writer, nodeHeader);
+                break;
+            case MagnesiumNode.NODE_LEAFSET_ORDERED:
+                streamLeafsetOrdered(writer, nodeHeader);
+                break;
+            case MagnesiumNode.NODE_CHOICE:
+                streamChoice(writer, nodeHeader);
+                break;
+            case MagnesiumNode.NODE_AUGMENTATION:
+                streamAugmentation(writer, nodeHeader);
+                break;
+            case MagnesiumNode.NODE_ANYXML:
+                streamAnyxml(writer, nodeHeader);
+                break;
+            case MagnesiumNode.NODE_LIST_ENTRY:
+                streamListEntry(writer, parent, nodeHeader);
+                break;
+            case MagnesiumNode.NODE_LEAFSET_ENTRY:
+                streamLeafsetEntry(writer, parent, nodeHeader);
+                break;
+            case MagnesiumNode.NODE_MAP_ENTRY:
+                streamMapEntry(writer, parent, nodeHeader);
+                break;
+            default:
+                throw new InvalidNormalizedNodeStreamException("Unexpected node header " + nodeHeader);
+        }
+    }
+
+    private void streamAnyxml(final NormalizedNodeStreamWriter writer, final byte nodeHeader) throws IOException {
+        final NodeIdentifier identifier = decodeNodeIdentifier(nodeHeader);
+        LOG.trace("Streaming anyxml node {}", identifier);
+
+        final DOMSource value = readDOMSource();
+        if (writer.startAnyxmlNode(identifier, DOMSource.class)) {
+            writer.domSourceValue(value);
+            writer.endNode();
+        }
+    }
+
+    private void streamAugmentation(final NormalizedNodeStreamWriter writer, final byte nodeHeader) throws IOException {
+        final var augIdentifier = decodeAugmentationIdentifier(nodeHeader);
+        LOG.trace("Streaming augmentation node {}", augIdentifier);
+        for (byte nodeType = input.readByte(); nodeType != MagnesiumNode.NODE_END; nodeType = input.readByte()) {
+            streamNormalizedNode(writer, augIdentifier, nodeType);
+        }
+    }
+
+    private void streamChoice(final NormalizedNodeStreamWriter writer, final byte nodeHeader) throws IOException {
+        final NodeIdentifier identifier = decodeNodeIdentifier(nodeHeader);
+        LOG.trace("Streaming choice node {}", identifier);
+        writer.startChoiceNode(identifier, UNKNOWN_SIZE);
+        commonStreamContainer(writer, identifier);
+    }
+
+    private void streamContainer(final NormalizedNodeStreamWriter writer, final byte nodeHeader) throws IOException {
+        final NodeIdentifier identifier = decodeNodeIdentifier(nodeHeader);
+        LOG.trace("Streaming container node {}", identifier);
+        writer.startContainerNode(identifier, UNKNOWN_SIZE);
+        commonStreamContainer(writer, identifier);
+    }
+
+    private void streamLeaf(final NormalizedNodeStreamWriter writer, final Object parent, final byte nodeHeader)
+            throws IOException {
+        final NodeIdentifier identifier = decodeNodeIdentifier(nodeHeader);
+        LOG.trace("Streaming leaf node {}", identifier);
+        writer.startLeafNode(identifier);
+
+        final Object value;
+        if ((nodeHeader & MagnesiumNode.PREDICATE_ONE) == MagnesiumNode.PREDICATE_ONE) {
+            if (!(parent instanceof NodeIdentifierWithPredicates nip)) {
+                throw new InvalidNormalizedNodeStreamException("Invalid predicate leaf " + identifier + " in parent "
+                        + parent);
+            }
+
+            value = nip.getValue(identifier.getNodeType());
+            if (value == null) {
+                throw new InvalidNormalizedNodeStreamException("Failed to find predicate leaf " + identifier
+                    + " in parent " + parent);
+            }
+        } else {
+            value = readLeafValue();
+        }
+
+        writer.scalarValue(value);
+        writer.endNode();
+    }
+
+    private void streamLeafset(final NormalizedNodeStreamWriter writer, final byte nodeHeader) throws IOException {
+        final NodeIdentifier identifier = decodeNodeIdentifier(nodeHeader);
+        LOG.trace("Streaming leaf set node {}", identifier);
+        writer.startLeafSet(identifier, UNKNOWN_SIZE);
+        commonStreamContainer(writer, identifier);
+    }
+
+    private void streamLeafsetOrdered(final NormalizedNodeStreamWriter writer, final byte nodeHeader)
+            throws IOException {
+        final NodeIdentifier identifier = decodeNodeIdentifier(nodeHeader);
+        LOG.trace("Streaming ordered leaf set node {}", identifier);
+        writer.startOrderedLeafSet(identifier, UNKNOWN_SIZE);
+
+        commonStreamContainer(writer, identifier);
+    }
+
+    private void streamLeafsetEntry(final NormalizedNodeStreamWriter writer, final Object parent, final byte nodeHeader)
+            throws IOException {
+        final NodeIdentifier nodeId = decodeNodeIdentifier(nodeHeader, parent);
+        final Object value = readLeafValue();
+        final NodeWithValue<Object> leafIdentifier = new NodeWithValue<>(nodeId.getNodeType(), value);
+        LOG.trace("Streaming leaf set entry node {}", leafIdentifier);
+        writer.startLeafSetEntryNode(leafIdentifier);
+        writer.scalarValue(value);
+        writer.endNode();
+    }
+
+    private void streamList(final NormalizedNodeStreamWriter writer, final byte nodeHeader) throws IOException {
+        final NodeIdentifier identifier = decodeNodeIdentifier(nodeHeader);
+        writer.startUnkeyedList(identifier, UNKNOWN_SIZE);
+        commonStreamContainer(writer, identifier);
+    }
+
+    private void streamListEntry(final NormalizedNodeStreamWriter writer, final Object parent, final byte nodeHeader)
+            throws IOException {
+        final NodeIdentifier identifier = decodeNodeIdentifier(nodeHeader, parent);
+        LOG.trace("Streaming unkeyed list item node {}", identifier);
+        writer.startUnkeyedListItem(identifier, UNKNOWN_SIZE);
+        commonStreamContainer(writer, identifier);
+    }
+
+    private void streamMap(final NormalizedNodeStreamWriter writer, final byte nodeHeader) throws IOException {
+        final NodeIdentifier identifier = decodeNodeIdentifier(nodeHeader);
+        LOG.trace("Streaming map node {}", identifier);
+        writer.startMapNode(identifier, UNKNOWN_SIZE);
+        commonStreamContainer(writer, identifier);
+    }
+
+    private void streamMapOrdered(final NormalizedNodeStreamWriter writer, final byte nodeHeader) throws IOException {
+        final NodeIdentifier identifier = decodeNodeIdentifier(nodeHeader);
+        LOG.trace("Streaming ordered map node {}", identifier);
+        writer.startOrderedMapNode(identifier, UNKNOWN_SIZE);
+        commonStreamContainer(writer, identifier);
+    }
+
+    private void streamMapEntry(final NormalizedNodeStreamWriter writer, final Object parent, final byte nodeHeader)
+            throws IOException {
+        final NodeIdentifier nodeId = decodeNodeIdentifier(nodeHeader, parent);
+
+        final int size = switch (mask(nodeHeader, MagnesiumNode.PREDICATE_MASK)) {
+            case MagnesiumNode.PREDICATE_ZERO -> 0;
+            case MagnesiumNode.PREDICATE_ONE -> 1;
+            case MagnesiumNode.PREDICATE_1B -> input.readUnsignedByte();
+            case MagnesiumNode.PREDICATE_4B -> input.readInt();
+            default ->
+                // ISE on purpose: this should never ever happen
+                throw new IllegalStateException("Failed to decode NodeIdentifierWithPredicates size from header "
+                    + nodeHeader);
+        };
+        final NodeIdentifierWithPredicates identifier = readNodeIdentifierWithPredicates(nodeId.getNodeType(), size);
+        LOG.trace("Streaming map entry node {}", identifier);
+        writer.startMapEntryNode(identifier, UNKNOWN_SIZE);
+        commonStreamContainer(writer, identifier);
+    }
+
+    private void commonStreamContainer(final NormalizedNodeStreamWriter writer, final PathArgument parent)
+            throws IOException {
+        for (byte nodeType = input.readByte(); nodeType != MagnesiumNode.NODE_END; nodeType = input.readByte()) {
+            streamNormalizedNode(writer, parent, nodeType);
+        }
+        writer.endNode();
+    }
+
+    private @NonNull NodeIdentifier decodeNodeIdentifier() throws IOException {
+        final QNameModule module = decodeQNameModule();
+        final String localName = readRefString();
+        final NodeIdentifier nodeId;
+        try {
+            nodeId = QNameFactory.getNodeIdentifier(module, localName);
+        } catch (ExecutionException e) {
+            throw new InvalidNormalizedNodeStreamException("Illegal QName module=" + module + " localName="
+                    + localName, e);
+        }
+
+        codedNodeIdentifiers.add(nodeId);
+        return nodeId;
+    }
+
+    private NodeIdentifier decodeNodeIdentifier(final byte nodeHeader) throws IOException {
+        return decodeNodeIdentifier(nodeHeader, null);
+    }
+
+    private NodeIdentifier decodeNodeIdentifier(final byte nodeHeader, final Object parent) throws IOException {
+        final int index;
+        switch (nodeHeader & MagnesiumNode.ADDR_MASK) {
+            case MagnesiumNode.ADDR_DEFINE:
+                return readNodeIdentifier();
+            case MagnesiumNode.ADDR_LOOKUP_1B:
+                index = input.readUnsignedByte();
+                break;
+            case MagnesiumNode.ADDR_LOOKUP_4B:
+                index = input.readInt();
+                break;
+            case MagnesiumNode.ADDR_PARENT:
+                if (parent instanceof NodeIdentifier nid) {
+                    return nid;
+                }
+                throw new InvalidNormalizedNodeStreamException("Invalid node identifier reference to parent " + parent);
+            default:
+                throw new InvalidNormalizedNodeStreamException("Unexpected node identifier addressing in header "
+                        + nodeHeader);
+        }
+
+        try {
+            return codedNodeIdentifiers.get(index);
+        } catch (IndexOutOfBoundsException e) {
+            throw new InvalidNormalizedNodeStreamException("Invalid QName reference " + index, e);
+        }
+    }
+
+    private LegacyAugmentationIdentifier decodeAugmentationIdentifier(final byte nodeHeader) throws IOException {
+        final int index;
+        switch (nodeHeader & MagnesiumNode.ADDR_MASK) {
+            case MagnesiumNode.ADDR_DEFINE:
+                return readAugmentationIdentifier();
+            case MagnesiumNode.ADDR_LOOKUP_1B:
+                index = input.readUnsignedByte();
+                break;
+            case MagnesiumNode.ADDR_LOOKUP_4B:
+                index = input.readInt();
+                break;
+            default:
+                throw new InvalidNormalizedNodeStreamException(
+                    "Unexpected augmentation identifier addressing in header " + nodeHeader);
+        }
+
+        try {
+            return codedAugments.get(index);
+        } catch (IndexOutOfBoundsException e) {
+            throw new InvalidNormalizedNodeStreamException("Invalid augmentation identifier reference " + index, e);
+        }
+    }
+
+    @Override
+    public YangInstanceIdentifier readYangInstanceIdentifier() throws IOException {
+        final byte type = input.readByte();
+        if (type == MagnesiumValue.YIID) {
+            return readYangInstanceIdentifier(input.readInt());
+        } else if (type >= MagnesiumValue.YIID_0) {
+            // Note 'byte' is range limited, so it is always '&& type <= MagnesiumValue.YIID_31'
+            return readYangInstanceIdentifier(type - MagnesiumValue.YIID_0);
+        } else {
+            throw new InvalidNormalizedNodeStreamException("Unexpected YangInstanceIdentifier type " + type);
+        }
+    }
+
+    private @NonNull YangInstanceIdentifier readYangInstanceIdentifier(final int size) throws IOException {
+        if (size > 0) {
+            final Builder<PathArgument> builder = ImmutableList.builderWithExpectedSize(size);
+            for (int i = 0; i < size; ++i) {
+                builder.add(readPathArgument());
+            }
+            return YangInstanceIdentifier.of(builder.build());
+        } else if (size == 0) {
+            return YangInstanceIdentifier.of();
+        } else {
+            throw new InvalidNormalizedNodeStreamException("Invalid YangInstanceIdentifier size " + size);
+        }
+    }
+
+    @Override
+    public QName readQName() throws IOException {
+        final byte type = input.readByte();
+        return switch (type) {
+            case MagnesiumValue.QNAME -> decodeQName();
+            case MagnesiumValue.QNAME_REF_1B -> decodeQNameRef1();
+            case MagnesiumValue.QNAME_REF_2B -> decodeQNameRef2();
+            case MagnesiumValue.QNAME_REF_4B -> decodeQNameRef4();
+            default -> throw new InvalidNormalizedNodeStreamException("Unexpected QName type " + type);
+        };
+    }
+
+    @Override
+    @Deprecated(since = "11.0.0", forRemoval = true)
+    public Either<PathArgument, LegacyPathArgument> readLegacyPathArgument() throws IOException {
+        final byte header = input.readByte();
+        return switch (header & MagnesiumPathArgument.TYPE_MASK) {
+            case MagnesiumPathArgument.AUGMENTATION_IDENTIFIER -> Either.ofSecond(readAugmentationIdentifier(header));
+            case MagnesiumPathArgument.NODE_IDENTIFIER -> {
+                verifyPathIdentifierOnly(header);
+                yield Either.ofFirst(readNodeIdentifier(header));
+            }
+            case MagnesiumPathArgument.NODE_IDENTIFIER_WITH_PREDICATES ->
+                Either.ofFirst(readNodeIdentifierWithPredicates(header));
+            case MagnesiumPathArgument.NODE_WITH_VALUE -> {
+                verifyPathIdentifierOnly(header);
+                yield Either.ofFirst(readNodeWithValue(header));
+            }
+            case MagnesiumPathArgument.MOUNTPOINT_IDENTIFIER -> {
+                verifyPathIdentifierOnly(header);
+                yield Either.ofSecond(new LegacyMountPointIdentifier(readNodeIdentifier(header).getNodeType()));
+            }
+            default -> throw new InvalidNormalizedNodeStreamException("Unexpected PathArgument header " + header);
+        };
+    }
+
+    private @NonNull LegacyAugmentationIdentifier readAugmentationIdentifier() throws IOException {
+        final var result = readAugmentationIdentifier(input.readInt());
+        codedAugments.add(result);
+        return result;
+    }
+
+    private @NonNull LegacyAugmentationIdentifier readAugmentationIdentifier(final byte header) throws IOException {
+        final byte count = mask(header, MagnesiumPathArgument.AID_COUNT_MASK);
+        return switch (count) {
+            case MagnesiumPathArgument.AID_COUNT_1B -> readAugmentationIdentifier(input.readUnsignedByte());
+            case MagnesiumPathArgument.AID_COUNT_2B -> readAugmentationIdentifier(input.readUnsignedShort());
+            case MagnesiumPathArgument.AID_COUNT_4B -> readAugmentationIdentifier(input.readInt());
+            default -> readAugmentationIdentifier(rshift(count, MagnesiumPathArgument.AID_COUNT_SHIFT));
+        };
+    }
+
+    private @NonNull LegacyAugmentationIdentifier readAugmentationIdentifier(final int size) throws IOException {
+        if (size > 0) {
+            final var qnames = ImmutableSet.<QName>builderWithExpectedSize(size);
+            for (int i = 0; i < size; ++i) {
+                qnames.add(readQName());
+            }
+            return new LegacyAugmentationIdentifier(qnames.build());
+        } else if (size == 0) {
+            return EMPTY_AID;
+        } else {
+            throw new InvalidNormalizedNodeStreamException("Invalid augmentation identifier size " + size);
+        }
+    }
+
+    private @NonNull NodeIdentifier readNodeIdentifier() throws IOException {
+        return decodeNodeIdentifier();
+    }
+
+    private @NonNull NodeIdentifier readNodeIdentifier(final byte header) throws IOException {
+        return switch (header & MagnesiumPathArgument.QNAME_MASK) {
+            case MagnesiumPathArgument.QNAME_DEF -> decodeNodeIdentifier();
+            case MagnesiumPathArgument.QNAME_REF_1B -> decodeNodeIdentifierRef1();
+            case MagnesiumPathArgument.QNAME_REF_2B -> decodeNodeIdentifierRef2();
+            case MagnesiumPathArgument.QNAME_REF_4B -> decodeNodeIdentifierRef4();
+            default -> throw new InvalidNormalizedNodeStreamException("Invalid QName coding in " + header);
+        };
+    }
+
+    private @NonNull  NodeIdentifierWithPredicates readNodeIdentifierWithPredicates(final byte header)
+            throws IOException {
+        final QName qname = readNodeIdentifier(header).getNodeType();
+        return switch (mask(header, MagnesiumPathArgument.SIZE_MASK)) {
+            case MagnesiumPathArgument.SIZE_1B -> readNodeIdentifierWithPredicates(qname, input.readUnsignedByte());
+            case MagnesiumPathArgument.SIZE_2B -> readNodeIdentifierWithPredicates(qname, input.readUnsignedShort());
+            case MagnesiumPathArgument.SIZE_4B -> readNodeIdentifierWithPredicates(qname, input.readInt());
+            default -> readNodeIdentifierWithPredicates(qname, rshift(header, MagnesiumPathArgument.SIZE_SHIFT));
+        };
+    }
+
+    private @NonNull NodeIdentifierWithPredicates readNodeIdentifierWithPredicates(final QName qname, final int size)
+            throws IOException {
+        if (size == 1) {
+            return NodeIdentifierWithPredicates.of(qname, readQName(), readLeafValue());
+        } else if (size > 1) {
+            final ImmutableMap.Builder<QName, Object> builder = ImmutableMap.builderWithExpectedSize(size);
+            for (int i = 0; i < size; ++i) {
+                builder.put(readQName(), readLeafValue());
+            }
+            return NodeIdentifierWithPredicates.of(qname, builder.build());
+        } else if (size == 0) {
+            return NodeIdentifierWithPredicates.of(qname);
+        } else {
+            throw new InvalidNormalizedNodeStreamException("Invalid predicate count " + size);
+        }
+    }
+
+    private @NonNull NodeWithValue<?> readNodeWithValue(final byte header) throws IOException {
+        final QName qname = readNodeIdentifier(header).getNodeType();
+        return new NodeWithValue<>(qname, readLeafValue());
+    }
+
+    private static void verifyPathIdentifierOnly(final byte header) throws InvalidNormalizedNodeStreamException {
+        if (mask(header, MagnesiumPathArgument.SIZE_MASK) != 0) {
+            throw new InvalidNormalizedNodeStreamException("Invalid path argument header " + header);
+        }
+    }
+
+    private @NonNull NodeIdentifier decodeNodeIdentifierRef1() throws IOException {
+        return lookupNodeIdentifier(input.readUnsignedByte());
+    }
+
+    private @NonNull NodeIdentifier decodeNodeIdentifierRef2() throws IOException {
+        return lookupNodeIdentifier(input.readUnsignedShort() + 256);
+    }
+
+    private @NonNull NodeIdentifier decodeNodeIdentifierRef4() throws IOException {
+        return lookupNodeIdentifier(input.readInt());
+    }
+
+    private @NonNull QName decodeQName() throws IOException {
+        return decodeNodeIdentifier().getNodeType();
+    }
+
+    private @NonNull QName decodeQNameRef1() throws IOException {
+        return lookupQName(input.readUnsignedByte());
+    }
+
+    private @NonNull QName decodeQNameRef2() throws IOException {
+        return lookupQName(input.readUnsignedShort() + 256);
+    }
+
+    private @NonNull QName decodeQNameRef4() throws IOException {
+        return lookupQName(input.readInt());
+    }
+
+    private @NonNull QNameModule decodeQNameModule() throws IOException {
+        final byte type = input.readByte();
+        final int index;
+        switch (type) {
+            case MagnesiumValue.MODREF_1B:
+                index = input.readUnsignedByte();
+                break;
+            case MagnesiumValue.MODREF_2B:
+                index = input.readUnsignedShort() + 256;
+                break;
+            case MagnesiumValue.MODREF_4B:
+                index = input.readInt();
+                break;
+            default:
+                return decodeQNameModuleDef(type);
+        }
+
+        try {
+            return codedModules.get(index);
+        } catch (IndexOutOfBoundsException e) {
+            throw new InvalidNormalizedNodeStreamException("Invalid QNameModule reference " + index, e);
+        }
+    }
+
+    // QNameModule definition, i.e. two encoded strings
+    private @NonNull QNameModule decodeQNameModuleDef(final byte type) throws IOException {
+        final String namespace = readRefString(type);
+
+        final byte refType = input.readByte();
+        final String revision = refType == MagnesiumValue.STRING_EMPTY ? null : readRefString(refType);
+        final QNameModule module;
+        try {
+            module = QNameFactory.createModule(namespace, revision);
+        } catch (UncheckedExecutionException e) {
+            throw new InvalidNormalizedNodeStreamException("Illegal QNameModule ns=" + namespace + " rev=" + revision,
+                e);
+        }
+
+        codedModules.add(module);
+        return module;
+    }
+
+    private @NonNull String readRefString() throws IOException {
+        return readRefString(input.readByte());
+    }
+
+    private @NonNull String readRefString(final byte type) throws IOException {
+        final String str;
+        switch (type) {
+            case MagnesiumValue.STRING_REF_1B:
+                return lookupString(input.readUnsignedByte());
+            case MagnesiumValue.STRING_REF_2B:
+                return lookupString(input.readUnsignedShort() + 256);
+            case MagnesiumValue.STRING_REF_4B:
+                return lookupString(input.readInt());
+            case MagnesiumValue.STRING_EMPTY:
+                return "";
+            case MagnesiumValue.STRING_2B:
+                str = readString2();
+                break;
+            case MagnesiumValue.STRING_4B:
+                str = readString4();
+                break;
+            case MagnesiumValue.STRING_CHARS:
+                str = readCharsString();
+                break;
+            case MagnesiumValue.STRING_UTF:
+                str = input.readUTF();
+                break;
+            default:
+                throw new InvalidNormalizedNodeStreamException("Unexpected String type " + type);
+        }
+
+        // TODO: consider interning Strings -- that would help with bits, but otherwise it's probably not worth it
+        codedStrings.add(verifyNotNull(str));
+        return str;
+    }
+
+    private @NonNull String readString() throws IOException {
+        final byte type = input.readByte();
+        return switch (type) {
+            case MagnesiumValue.STRING_EMPTY -> "";
+            case MagnesiumValue.STRING_UTF -> input.readUTF();
+            case MagnesiumValue.STRING_2B -> readString2();
+            case MagnesiumValue.STRING_4B -> readString4();
+            case MagnesiumValue.STRING_CHARS -> readCharsString();
+            default -> throw new InvalidNormalizedNodeStreamException("Unexpected String type " + type);
+        };
+    }
+
+    private @NonNull String readString2() throws IOException {
+        return readByteString(input.readUnsignedShort());
+    }
+
+    private @NonNull String readString4() throws IOException {
+        return readByteString(input.readInt());
+    }
+
+    private @NonNull String readByteString(final int size) throws IOException {
+        if (size > 0) {
+            final byte[] bytes = new byte[size];
+            input.readFully(bytes);
+            return new String(bytes, StandardCharsets.UTF_8);
+        } else if (size == 0) {
+            return "";
+        } else {
+            throw new InvalidNormalizedNodeStreamException("Invalid String bytes length " + size);
+        }
+    }
+
+    private @NonNull String readCharsString() throws IOException {
+        final int size = input.readInt();
+        if (size > 0) {
+            final char[] chars = new char[size];
+            for (int i = 0; i < size; ++i) {
+                chars[i] = input.readChar();
+            }
+            return String.valueOf(chars);
+        } else if (size == 0) {
+            return "";
+        } else {
+            throw new InvalidNormalizedNodeStreamException("Invalid String chars length " + size);
+        }
+    }
+
+    private @NonNull NodeIdentifier lookupNodeIdentifier(final int index) throws InvalidNormalizedNodeStreamException {
+        try {
+            return codedNodeIdentifiers.get(index);
+        } catch (IndexOutOfBoundsException e) {
+            throw new InvalidNormalizedNodeStreamException("Invalid QName reference " + index, e);
+        }
+    }
+
+    private @NonNull QName lookupQName(final int index) throws InvalidNormalizedNodeStreamException {
+        return lookupNodeIdentifier(index).getNodeType();
+    }
+
+    private @NonNull String lookupString(final int index) throws InvalidNormalizedNodeStreamException {
+        try {
+            return codedStrings.get(index);
+        } catch (IndexOutOfBoundsException e) {
+            throw new InvalidNormalizedNodeStreamException("Invalid String reference " + index, e);
+        }
+    }
+
+    private @NonNull DOMSource readDOMSource() throws IOException {
+        final String str = readString();
+        try {
+            return new DOMSource(UntrustedXML.newDocumentBuilder().parse(new InputSource(new StringReader(str)))
+                .getDocumentElement());
+        } catch (SAXException e) {
+            throw new IOException("Error parsing XML: " + str, e);
+        }
+    }
+
+    private @NonNull Object readLeafValue() throws IOException {
+        final byte type = input.readByte();
+        switch (type) {
+            case MagnesiumValue.BOOLEAN_FALSE:
+                return Boolean.FALSE;
+            case MagnesiumValue.BOOLEAN_TRUE:
+                return Boolean.TRUE;
+            case MagnesiumValue.EMPTY:
+                return Empty.value();
+            case MagnesiumValue.INT8:
+                return input.readByte();
+            case MagnesiumValue.INT8_0:
+                return INT8_0;
+            case MagnesiumValue.INT16:
+                return input.readShort();
+            case MagnesiumValue.INT16_0:
+                return INT16_0;
+            case MagnesiumValue.INT32:
+                return input.readInt();
+            case MagnesiumValue.INT32_0:
+                return INT32_0;
+            case MagnesiumValue.INT32_2B:
+                return input.readShort() & 0xFFFF;
+            case MagnesiumValue.INT64:
+                return input.readLong();
+            case MagnesiumValue.INT64_0:
+                return INT64_0;
+            case MagnesiumValue.INT64_4B:
+                return input.readInt() & 0xFFFFFFFFL;
+            case MagnesiumValue.UINT8:
+                return Uint8.fromByteBits(input.readByte());
+            case MagnesiumValue.UINT8_0:
+                return Uint8.ZERO;
+            case MagnesiumValue.UINT16:
+                return Uint16.fromShortBits(input.readShort());
+            case MagnesiumValue.UINT16_0:
+                return Uint16.ZERO;
+            case MagnesiumValue.UINT32:
+                return Uint32.fromIntBits(input.readInt());
+            case MagnesiumValue.UINT32_0:
+                return Uint32.ZERO;
+            case MagnesiumValue.UINT32_2B:
+                return Uint32.fromIntBits(input.readShort() & 0xFFFF);
+            case MagnesiumValue.UINT64:
+                return Uint64.fromLongBits(input.readLong());
+            case MagnesiumValue.UINT64_0:
+                return Uint64.ZERO;
+            case MagnesiumValue.UINT64_4B:
+                return Uint64.fromLongBits(input.readInt() & 0xFFFFFFFFL);
+            case MagnesiumValue.BIGDECIMAL:
+                // FIXME: use string -> BigDecimal cache
+                return Decimal64.valueOf(input.readUTF());
+            case MagnesiumValue.BIGINTEGER:
+                throw new InvalidNormalizedNodeStreamException("BigInteger coding is not supported");
+            case MagnesiumValue.STRING_EMPTY:
+                return "";
+            case MagnesiumValue.STRING_UTF:
+                return input.readUTF();
+            case MagnesiumValue.STRING_2B:
+                return readString2();
+            case MagnesiumValue.STRING_4B:
+                return readString4();
+            case MagnesiumValue.STRING_CHARS:
+                return readCharsString();
+            case MagnesiumValue.BINARY_0:
+                return BINARY_0;
+            case MagnesiumValue.BINARY_1B:
+                return readBinary(128 + input.readUnsignedByte());
+            case MagnesiumValue.BINARY_2B:
+                return readBinary(384 + input.readUnsignedShort());
+            case MagnesiumValue.BINARY_4B:
+                return readBinary(input.readInt());
+            case MagnesiumValue.YIID_0:
+                return YangInstanceIdentifier.of();
+            case MagnesiumValue.YIID:
+                return readYangInstanceIdentifier(input.readInt());
+            case MagnesiumValue.QNAME:
+                return decodeQName();
+            case MagnesiumValue.QNAME_REF_1B:
+                return decodeQNameRef1();
+            case MagnesiumValue.QNAME_REF_2B:
+                return decodeQNameRef2();
+            case MagnesiumValue.QNAME_REF_4B:
+                return decodeQNameRef4();
+            case MagnesiumValue.BITS_0:
+                return ImmutableSet.of();
+            case MagnesiumValue.BITS_1B:
+                return readBits(input.readUnsignedByte() + 29);
+            case MagnesiumValue.BITS_2B:
+                return readBits(input.readUnsignedShort() + 285);
+            case MagnesiumValue.BITS_4B:
+                return readBits(input.readInt());
+
+            default:
+                if (type > MagnesiumValue.BINARY_0 && type <= MagnesiumValue.BINARY_127) {
+                    return readBinary(type - MagnesiumValue.BINARY_0);
+                } else if (type > MagnesiumValue.BITS_0 && type < MagnesiumValue.BITS_1B) {
+                    return readBits(type - MagnesiumValue.BITS_0);
+                } else if (type > MagnesiumValue.YIID_0) {
+                    // Note 'byte' is range limited, so it is always '&& type <= MagnesiumValue.YIID_31'
+                    return readYangInstanceIdentifier(type - MagnesiumValue.YIID_0);
+                } else {
+                    throw new InvalidNormalizedNodeStreamException("Invalid value type " + type);
+                }
+        }
+    }
+
+    private byte @NonNull [] readBinary(final int size) throws IOException {
+        if (size > 0) {
+            final byte[] ret = new byte[size];
+            input.readFully(ret);
+            return ret;
+        } else if (size == 0) {
+            return BINARY_0;
+        } else {
+            throw new InvalidNormalizedNodeStreamException("Invalid binary length " + size);
+        }
+    }
+
+    private @NonNull ImmutableSet<String> readBits(final int size) throws IOException {
+        if (size > 0) {
+            final ImmutableSet.Builder<String> builder = ImmutableSet.builder();
+            for (int i = 0; i < size; ++i) {
+                builder.add(readRefString());
+            }
+            return builder.build();
+        } else if (size == 0) {
+            return ImmutableSet.of();
+        } else {
+            throw new InvalidNormalizedNodeStreamException("Invalid bits length " + size);
+        }
+    }
+
+    private static byte mask(final byte header, final byte mask) {
+        return (byte) (header & mask);
+    }
+
+    private static int rshift(final byte header, final byte shift) {
+        return (header & 0xFF) >>> shift;
     }
 }
diff --git a/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/NeonSR2NormalizedNodeInputStreamReader.java b/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/NeonSR2NormalizedNodeInputStreamReader.java
deleted file mode 100644 (file)
index 1eb8412..0000000
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright (c) 2019 PANTHEON.tech, s.r.o. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.yangtools.yang.data.codec.binfmt;
-
-import static com.google.common.base.Verify.verify;
-
-import java.io.DataInput;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.common.QNameModule;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
-
-/**
- * Neon SR2 specialization of AbstractLithiumDataInput. Unlike its Lithium counterpart, this format uses coding for
- * QNameModules, QNames, NodeIdentifiers and AugmentationIdentifiers, thus reducing stream duplication.
- */
-final class NeonSR2NormalizedNodeInputStreamReader extends AbstractLithiumDataInput {
-    private final ArrayList<NodeIdentifier> codedNodeIdentifiers = new ArrayList<>();
-    private final List<LegacyAugmentationIdentifier> codedAugments = new ArrayList<>();
-    private final List<QNameModule> codedModules = new ArrayList<>();
-    private final List<QName> codedQNames = new ArrayList<>();
-
-    NeonSR2NormalizedNodeInputStreamReader(final DataInput input) {
-        super(input);
-    }
-
-    @Override
-    @Deprecated(since = "11.0.0", forRemoval = true)
-    public NormalizedNodeStreamVersion getVersion() {
-        return NormalizedNodeStreamVersion.NEON_SR2;
-    }
-
-    @Override
-    public QName readQName() throws IOException {
-        final byte valueType = readByte();
-        return switch (valueType) {
-            case NeonSR2Tokens.IS_QNAME_CODE -> codedQName(readInt());
-            case NeonSR2Tokens.IS_QNAME_VALUE -> rawQName();
-            default -> throw new IOException("Unhandled QName value type " + valueType);
-        };
-    }
-
-    @Override
-    LegacyAugmentationIdentifier readAugmentationIdentifier() throws IOException {
-        final byte valueType = readByte();
-        return switch (valueType) {
-            case NeonSR2Tokens.IS_AUGMENT_CODE -> codedAugmentId(readInt());
-            case NeonSR2Tokens.IS_AUGMENT_VALUE -> rawAugmentId();
-            default -> throw new IOException("Unhandled AugmentationIdentifier value type " + valueType);
-        };
-    }
-
-    @Override
-    NodeIdentifier readNodeIdentifier() throws IOException {
-        // NodeIdentifier rides on top of QName, with this method really saying 'interpret next QName as NodeIdentifier'
-        // to do that we inter-mingle with readQName()
-        final byte valueType = readByte();
-        return switch (valueType) {
-            case NeonSR2Tokens.IS_QNAME_CODE -> codedNodeIdentifier(readInt());
-            case NeonSR2Tokens.IS_QNAME_VALUE -> rawNodeIdentifier();
-            default -> throw new IOException("Unhandled NodeIdentifier value type " + valueType);
-        };
-    }
-
-    private QNameModule readModule() throws IOException {
-        final byte valueType = readByte();
-        return switch (valueType) {
-            case NeonSR2Tokens.IS_MODULE_CODE -> codedModule(readInt());
-            case NeonSR2Tokens.IS_MODULE_VALUE -> rawModule();
-            default -> throw new IOException("Unhandled QNameModule value type " + valueType);
-        };
-    }
-
-    private NodeIdentifier codedNodeIdentifier(final int code) throws IOException {
-        final NodeIdentifier existing = codedNodeIdentifiers.size() > code ? codedNodeIdentifiers.get(code) : null;
-        return existing != null ? existing : storeNodeIdentifier(code, codedQName(code));
-    }
-
-    private NodeIdentifier rawNodeIdentifier() throws IOException {
-        // Capture size before it incremented
-        final int code = codedQNames.size();
-        return storeNodeIdentifier(code, rawQName());
-    }
-
-    private NodeIdentifier storeNodeIdentifier(final int code, final QName qname) {
-        final NodeIdentifier ret = NodeIdentifier.create(qname);
-        final int size = codedNodeIdentifiers.size();
-
-        if (code >= size) {
-            // Null-fill others
-            codedNodeIdentifiers.ensureCapacity(code + 1);
-            for (int i = size; i < code; ++i) {
-                codedNodeIdentifiers.add(null);
-            }
-
-            codedNodeIdentifiers.add(ret);
-        } else {
-            final NodeIdentifier check = codedNodeIdentifiers.set(code, ret);
-            verify(check == null);
-        }
-
-        return ret;
-    }
-
-    private QName codedQName(final int code) throws IOException {
-        return getCode("QName", codedQNames, code);
-    }
-
-    private QName rawQName() throws IOException {
-        final String localName = readCodedString();
-        final QNameModule module = readModule();
-        final QName qname = QNameFactory.create(module, localName);
-        codedQNames.add(qname);
-        return qname;
-    }
-
-    private LegacyAugmentationIdentifier codedAugmentId(final int code) throws IOException {
-        return getCode("QName set", codedAugments, code);
-    }
-
-    private LegacyAugmentationIdentifier rawAugmentId() throws IOException {
-        final var aid = defaultReadAugmentationIdentifier();
-        codedAugments.add(aid);
-        return aid;
-    }
-
-    private QNameModule codedModule(final int code) throws IOException {
-        return getCode("Module", codedModules, code);
-    }
-
-    private QNameModule rawModule() throws IOException {
-        final String namespace = readCodedString();
-        final String revision = readCodedString();
-        final QNameModule mod = QNameFactory.createModule(namespace, revision);
-        codedModules.add(mod);
-        return mod;
-    }
-
-    private static <T> T getCode(final String name, final List<T> list, final int code) throws IOException {
-        try {
-            return list.get(code);
-        } catch (IndexOutOfBoundsException e) {
-            throw new IOException(name + " code " + code + " was not found", e);
-        }
-    }
-}
diff --git a/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/NeonSR2Tokens.java b/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/NeonSR2Tokens.java
deleted file mode 100644 (file)
index a75f1a5..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (c) 2019 PANTHEON.tech, s.r.o. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.yangtools.yang.data.codec.binfmt;
-
-/**
- * Tokens used in Neon SR2 encoding. Note that Neon SR2 builds on top of Lithium, hence the token values must never
- * overlap.
- */
-final class NeonSR2Tokens {
-    static final byte IS_QNAME_CODE = 4;
-    static final byte IS_QNAME_VALUE = 5;
-    static final byte IS_AUGMENT_CODE = 6;
-    static final byte IS_AUGMENT_VALUE = 7;
-    static final byte IS_MODULE_CODE = 8;
-    static final byte IS_MODULE_VALUE = 9;
-
-    private NeonSR2Tokens() {
-
-    }
-}
index 48f4defd4ec5378f8aed625c73c177723de6afb9..16b62a9a67ea4a1d258065ef4b6617d1aa38bd22 100644 (file)
@@ -18,69 +18,6 @@ import org.opendaylight.yangtools.yang.data.api.schema.ValueNode;
  */
 @NonNullByDefault
 public enum NormalizedNodeStreamVersion {
-    /**
-     * Original stream version, as shipped in OpenDaylight Lithium simultaneous release. The caveat here is that this
-     * version has augmented in OpenDaylight Oxygen to retrofit a non-null representation of the empty type.
-     *
-     * @deprecated This version cannot be written in and always required adaption. This version should not be relied
-     *             upon, as it is subject to removal in a future version.
-     */
-    @Deprecated(since = "11.0.0", forRemoval = true)
-    LITHIUM {
-        /**
-         * {@inheritDoc}
-         * @implSpec
-         *     This method always throws {@link UnsupportedOperationException}.
-         * @deprecated This version is a historic one and writeout is not supported
-         */
-        @Override
-        @Deprecated(since = "10.0.0", forRemoval = true)
-        public NormalizedNodeDataOutput newDataOutput(final DataOutput output) {
-            throw new UnsupportedOperationException();
-        }
-    },
-    /**
-     * Updated stream version, as shipped in OpenDaylight Neon SR2 release. Improves identifier encoding over
-     * {@link #LITHIUM}, so that QName caching is more effective.
-     *
-     * @deprecated This version cannot be written in and always required adaption. This version should not be relied
-     *             upon, as it is subject to removal in a future version.
-     */
-    @Deprecated(since = "11.0.0", forRemoval = true)
-    NEON_SR2 {
-        /**
-         * {@inheritDoc}
-         * @implSpec
-         *     This method always throws {@link UnsupportedOperationException}.
-         * @deprecated This version is a historic one and writeout is not supported
-         */
-        @Override
-        @Deprecated(since = "10.0.0", forRemoval = true)
-        public NormalizedNodeDataOutput newDataOutput(final DataOutput output) {
-            throw new UnsupportedOperationException();
-        }
-    },
-    /**
-     * First shipping in Sodium SR1. Improved stream coding to eliminate redundancies present in {@link #NEON_SR2}.
-     * Supports {@code Uint8} et al. as well as {@link BigInteger}.
-     *
-     * @deprecated This version cannot be written in and always required adaption. This version should not be relied
-     *             upon, as it is subject to removal in a future version.
-     */
-    @Deprecated(since = "11.0.0", forRemoval = true)
-    SODIUM_SR1 {
-        /**
-         * {@inheritDoc}
-         * @implSpec
-         *     This method always throws {@link UnsupportedOperationException}.
-         * @deprecated This version is a historic one and writeout is not supported
-         */
-        @Override
-        @Deprecated(since = "10.0.0", forRemoval = true)
-        public NormalizedNodeDataOutput newDataOutput(final DataOutput output) {
-            throw new UnsupportedOperationException();
-        }
-    },
     /**
      * First shipping is Magnesium. Does not support {@link BigInteger} mirroring it being superseded by {@link Uint64}
      * in {@link ValueNode#body()}.
diff --git a/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/SodiumSR1DataInput.java b/codec/yang-data-codec-binfmt/src/main/java/org/opendaylight/yangtools/yang/data/codec/binfmt/SodiumSR1DataInput.java
deleted file mode 100644 (file)
index aa748d2..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (c) 2019 PANTHEON.tech, s.r.o. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.yangtools.yang.data.codec.binfmt;
-
-import java.io.DataInput;
-import java.io.IOException;
-import java.math.BigInteger;
-
-final class SodiumSR1DataInput extends AbstractMagnesiumDataInput {
-    SodiumSR1DataInput(final DataInput input) {
-        super(input);
-    }
-
-    @Override
-    @Deprecated(since = "11.0.0", forRemoval = true)
-    public NormalizedNodeStreamVersion getVersion() {
-        return NormalizedNodeStreamVersion.SODIUM_SR1;
-    }
-
-    @Override
-    BigInteger readBigInteger() throws IOException {
-        // FIXME: use string -> BigInteger cache
-        return new BigInteger(input.readUTF());
-    }
-}
index 7dbb80d5014f53a2192deed1c26549eae7cf5bd1..765c31b61ff20d03a920afa8076837efdae084d6 100644 (file)
@@ -10,19 +10,16 @@ package org.opendaylight.yangtools.yang.data.codec.binfmt;
 final class TokenTypes {
     static final byte SIGNATURE_MARKER = (byte) 0xab;
 
-    /**
-     * Original stream version. Uses a per-stream dictionary for strings. QNames are serialized as three strings.
-     */
-    static final short LITHIUM_VERSION = 1;
-    /**
-     * Revised stream version. Unlike {@link #LITHIUM_VERSION}, QNames and QNameModules are using a per-stream
-     * dictionary, too.
-     */
-    static final short NEON_SR2_VERSION = 2;
-    /**
-     * From-scratch designed version shipping in Sodium SR1.
-     */
-    static final short SODIUM_SR1_VERSION = 3;
+    // Original stream version. Uses a per-stream dictionary for strings. QNames are serialized as three strings.
+    // LITHIUM_VERSION = 1;
+    //
+    // Revised stream version. Unlike {@link #LITHIUM_VERSION}, QNames and QNameModules are using a per-stream
+    // dictionary, too.
+    // NEON_SR2_VERSION = 2;
+    //
+    // From-scratch designed version shipping in Sodium SR1.
+    // SODIUM_SR1_VERSION = 3;
+
     /**
      * Magnesium version. Structurally matches {@link #SODIUM_SR1_VERSION}, but does not allow BigIntegers to be
      * present.
index c2632e988577bcdad5aaee6c39420a68a7662bbe..5e25856d643a230c29f3538cbbd7796f32d32078 100644 (file)
@@ -33,9 +33,6 @@ final class VersionedNormalizedNodeDataInput extends ForwardingNormalizedNodeDat
 
         final short version = input.readShort();
         final NormalizedNodeDataInput ret = switch (version) {
-            case TokenTypes.LITHIUM_VERSION -> new LithiumNormalizedNodeInputStreamReader(input);
-            case TokenTypes.NEON_SR2_VERSION -> new NeonSR2NormalizedNodeInputStreamReader(input);
-            case TokenTypes.SODIUM_SR1_VERSION -> new SodiumSR1DataInput(input);
             case TokenTypes.MAGNESIUM_VERSION -> new MagnesiumDataInput(input);
             case TokenTypes.POTASSIUM_VERSION -> new PotassiumDataInput(input);
             default -> throw defunct("Unhandled stream version %s", version);