package org.apache.haox.asn1.type; import org.apache.haox.asn1.Asn1Factory; import org.apache.haox.asn1.LimitedByteBuffer; import org.apache.haox.asn1.TaggingOption; import java.io.IOException; import java.nio.ByteBuffer; /** * Asn1Item serves two purposes: * 1. Wrapping an existing Asn1Type value for Asn1Collection; * 2. Wrapping a half decoded value whose body content is left to be decoded later when appropriate. * Why not fully decoded at once? Lazy and decode on demand for collection, or impossible due to lacking * key parameters, like implicit encoded value for tagged value. * * For not fully decoded value, you tell your case using isSimple/isCollection/isTagged/isContextSpecific etc., * then call decodeValueAsSimple/decodeValueAsCollection/decodeValueAsImplicitTagged/decodeValueAsExplicitTagged etc. * to decode it fully. Or if you have already derived the value holder or the holder type, you can use decodeValueWith * or decodeValueAs with your holder or hodler type. */ public class Asn1Item extends AbstractAsn1Type<Asn1Type> { private LimitedByteBuffer bodyContent; public Asn1Item(Asn1Type value) { super(value.tagFlags(), value.tagNo(), value); } public Asn1Item(int tag, int tagNo, LimitedByteBuffer bodyContent) { super(tag, tagNo); this.bodyContent = bodyContent; } public LimitedByteBuffer getBodyContent() { return bodyContent; } @Override protected int encodingBodyLength() { if (getValue() != null) { return ((AbstractAsn1Type) getValue()).encodingBodyLength(); } return (int) bodyContent.hasLeft(); } @Override protected void encodeBody(ByteBuffer buffer) { if (getValue() != null) { ((AbstractAsn1Type) getValue()).encodeBody(buffer); } else { try { buffer.put(bodyContent.readAllLeftBytes()); } catch (IOException e) { throw new RuntimeException("Failed to read all left bytes from body content", e); } } } @Override protected void decodeBody(LimitedByteBuffer bodyContent) throws IOException { this.bodyContent = bodyContent; } public boolean isFullyDecoded() { return getValue() != null; } public void decodeValueAsSimple() throws IOException { if (getValue() != null) return; if (! isSimple()) { throw new IllegalArgumentException("Attempting to decode non-simple value as simple"); } Asn1Type value = Asn1Factory.create(tagNo()); decodeValueWith(value); } public void decodeValueAsCollection() throws IOException { if (getValue() != null) return; if (! isCollection()) { throw new IllegalArgumentException("Attempting to decode non-collection value as collection"); } Asn1Type value = Asn1Factory.create(tagNo()); decodeValueWith(value); } public void decodeValueAs(Class<? extends Asn1Type> type) throws IOException { Asn1Type value; try { value = type.newInstance(); } catch (Exception e) { throw new RuntimeException("Invalid type: " + type.getCanonicalName(), e); } decodeValueWith(value); } public void decodeValueWith(Asn1Type value) throws IOException { setValue(value); ((AbstractAsn1Type) value).decode(tagFlags(), tagNo(), bodyContent); } public void decodeValueAsImplicitTagged(int originalTag, int originalTagNo) throws IOException { if (! isTagged()) { throw new IllegalArgumentException("Attempting to decode non-tagged value using tagging way"); } Asn1Item taggedValue = new Asn1Item(originalTag, originalTagNo, getBodyContent()); decodeValueWith(taggedValue); } public void decodeValueAsExplicitTagged() throws IOException { if (! isTagged()) { throw new IllegalArgumentException("Attempting to decode non-tagged value using tagging way"); } Asn1Item taggedValue = decodeOne(getBodyContent()); decodeValueWith(taggedValue); } private void decodeValueWith(Asn1Item taggedValue) throws IOException { taggedValue.decodeValueAsSimple(); if (taggedValue.isFullyDecoded()) { setValue(taggedValue.getValue()); } else { setValue(taggedValue); } } public void decodeValueWith(Asn1Type value, TaggingOption taggingOption) throws IOException { if (! isTagged()) { throw new IllegalArgumentException("Attempting to decode non-tagged value using tagging way"); } ((AbstractAsn1Type) value).taggedDecode(tagFlags(), tagNo(), getBodyContent(), taggingOption); setValue(value); } }