| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License. |
| package common.asn1; |
| |
| import java.util.Arrays; |
| |
| import streamer.ByteBuffer; |
| |
| /** |
| * One or more elements of different types. |
| * |
| * Only prefixed tags are supported. |
| */ |
| public class Sequence extends Tag { |
| |
| public Tag[] tags; |
| |
| public Sequence(String name) { |
| super(name); |
| tagType = SEQUENCE; |
| // Sequence and SequenceOf are always encoded as constructed |
| constructed = true; |
| } |
| |
| @Override |
| public long calculateLengthOfValuePayload() { |
| long sum = 0; |
| |
| for (Tag tag : tags) { |
| long tagLength = tag.calculateFullLength(); |
| sum += tagLength; |
| } |
| |
| return sum; |
| } |
| |
| @Override |
| public void writeTagValuePayload(ByteBuffer buf) { |
| // Write tags |
| for (Tag tag : tags) { |
| tag.writeTag(buf); |
| } |
| } |
| |
| @Override |
| public void readTagValue(ByteBuffer buf, BerType typeAndFlags) { |
| // Type is already read by parent parser |
| |
| long length = buf.readBerLength(); |
| if (length > buf.remainderLength()) |
| throw new RuntimeException("BER sequence is too long: " + length + " bytes, while buffer remainder length is " + buf.remainderLength() + ". Data: " + buf |
| + "."); |
| |
| ByteBuffer value = buf.readBytes((int)length); |
| parseContent(value); |
| |
| value.unref(); |
| } |
| |
| protected void parseContent(ByteBuffer buf) { |
| for (int i = 0; buf.remainderLength() > 0 && i < tags.length; i++) { |
| BerType typeAndFlags = readBerType(buf); |
| |
| // If current tag does not match data in buffer |
| if (!tags[i].isTypeValid(typeAndFlags)) { |
| |
| // If tag is required, then throw exception |
| if (!tags[i].optional) { |
| throw new RuntimeException("[" + this + "] ERROR: Required tag is missed: " + tags[i] + ". Unexected tag type: " + typeAndFlags + ". Data: " + buf |
| + "."); |
| } else { |
| // One or more tags are omitted, so skip them |
| for (; i < tags.length; i++) { |
| if (tags[i].isTypeValid(typeAndFlags)) { |
| break; |
| } |
| } |
| |
| if (i >= tags.length || !tags[i].isTypeValid(typeAndFlags)) { |
| throw new RuntimeException("[" + this + "] ERROR: No more tags to read or skip, but some data still left in buffer. Unexected tag type: " |
| + typeAndFlags + ". Data: " + buf + "."); |
| } |
| } |
| } |
| |
| tags[i].readTag(buf, typeAndFlags); |
| } |
| |
| } |
| |
| @Override |
| public boolean isTypeValid(BerType typeAndFlags, boolean explicit) { |
| if (explicit) |
| return typeAndFlags.tagClass == tagClass && typeAndFlags.constructed && typeAndFlags.typeOrTagNumber == tagNumber; |
| else |
| // Sequences are always encoded as "constructed" in BER. |
| return typeAndFlags.tagClass == UNIVERSAL_CLASS && typeAndFlags.constructed && typeAndFlags.typeOrTagNumber == SEQUENCE; |
| } |
| |
| @Override |
| public Tag deepCopy(String suffix) { |
| return new Sequence(name + suffix).copyFrom(this); |
| } |
| |
| @Override |
| public Tag copyFrom(Tag tag) { |
| super.copyFrom(tag); |
| |
| if (tags.length != ((Sequence)tag).tags.length) |
| throw new RuntimeException("Incompatible sequences. This: " + this + ", another: " + tag + "."); |
| |
| for (int i = 0; i < tags.length; i++) { |
| tags[i].copyFrom(((Sequence)tag).tags[i]); |
| } |
| |
| return this; |
| } |
| |
| @Override |
| public String toString() { |
| return super.toString() + "{" + Arrays.toString(tags) + " }"; |
| } |
| |
| @Override |
| public boolean isValueSet() { |
| return tags != null; |
| } |
| |
| } |