+++ /dev/null
-/*
- * 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);
- };
- }
-}
+++ /dev/null
-/*
- * 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;
- }
-}
+++ /dev/null
-/*
- * 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
- }
-}
+++ /dev/null
-/*
- * 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());
- }
-}
+++ /dev/null
-/*
- * 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);
- }
- }
-}
+++ /dev/null
-/*
- * 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() {
-
- }
-}
+++ /dev/null
-/*
- * 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
- }
-}
*/
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);
}
}
@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;
}
}
+++ /dev/null
-/*
- * 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);
- }
- }
-}
+++ /dev/null
-/*
- * 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() {
-
- }
-}
*/
@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()}.
+++ /dev/null
-/*
- * 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());
- }
-}
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.
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);