BUG-8039: Enforce binary/string type length
[yangtools.git] / yang / yang-data-impl / src / main / java / org / opendaylight / yangtools / yang / data / impl / codec / BinaryStringCodec.java
index 04ba7211ea544d5d1403edb9c0509ce63ff6f0a5..467d226e777ad440e5a98815e77e8d080b1c9448 100644 (file)
@@ -8,19 +8,57 @@
 package org.opendaylight.yangtools.yang.data.impl.codec;
 
 import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableRangeSet;
+import com.google.common.collect.Range;
+import com.google.common.collect.RangeSet;
+import com.google.common.collect.TreeRangeSet;
 import com.google.common.io.BaseEncoding;
 import javax.xml.bind.DatatypeConverter;
 import org.opendaylight.yangtools.yang.data.api.codec.BinaryCodec;
 import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.LengthConstraint;
 
-final class BinaryStringCodec extends TypeDefinitionAwareCodec<byte[], BinaryTypeDefinition> implements BinaryCodec<String> {
+abstract class BinaryStringCodec extends TypeDefinitionAwareCodec<byte[], BinaryTypeDefinition>
+        implements BinaryCodec<String> {
+    private static final class Restricted extends BinaryStringCodec {
+        private final RangeSet<Integer> ranges;
 
-    private BinaryStringCodec(final Optional<BinaryTypeDefinition> typeDef) {
-        super(typeDef, byte[].class);
+        Restricted(final BinaryTypeDefinition typeDef) {
+            super(typeDef);
+
+            final RangeSet<Integer> r = TreeRangeSet.create();
+            for (LengthConstraint c : typeDef.getLengthConstraints()) {
+                r.add(Range.closed(c.getMin().intValue(), c.getMax().intValue()));
+            }
+
+            ranges = ImmutableRangeSet.copyOf(r);
+        }
+
+        @Override
+        void validate(final byte[] value) {
+            Preconditions.checkArgument(ranges.contains(value.length),
+                "Value length %s does not match constraints %s", value.length, ranges);
+        }
+    }
+
+    private static final class Unrestricted extends BinaryStringCodec {
+        Unrestricted(final BinaryTypeDefinition typeDef) {
+            super(typeDef);
+        }
+
+        @Override
+        void validate(final byte[] value) {
+            // No-op
+        }
+    }
+
+    BinaryStringCodec(final BinaryTypeDefinition typeDef) {
+        super(Optional.of(typeDef), byte[].class);
     }
 
-    static TypeDefinitionAwareCodec<?,BinaryTypeDefinition> from(final BinaryTypeDefinition type) {
-        return new BinaryStringCodec(Optional.fromNullable(type));
+    static TypeDefinitionAwareCodec<?, BinaryTypeDefinition> from(final BinaryTypeDefinition type) {
+        return type.getLengthConstraints().isEmpty() ? new Unrestricted(type) : new Restricted(type);
     }
 
     @Override
@@ -30,6 +68,14 @@ final class BinaryStringCodec extends TypeDefinitionAwareCodec<byte[], BinaryTyp
 
     @Override
     public byte[] deserialize(final String stringRepresentation) {
-        return stringRepresentation == null ? null : DatatypeConverter.parseBase64Binary(stringRepresentation);
+        if (stringRepresentation == null) {
+            return null;
+        }
+
+        final byte[] ret = DatatypeConverter.parseBase64Binary(stringRepresentation);
+        validate(ret);
+        return ret;
     }
+
+    abstract void validate(byte[] value);
 }