001/*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License").  You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
010 * or http://forgerock.org/license/CDDLv1.0.html.
011 * See the License for the specific language governing permissions
012 * and limitations under the License.
013 *
014 * When distributing Covered Code, include this CDDL HEADER in each
015 * file and include the License file at legal-notices/CDDLv1_0.txt.
016 * If applicable, add the following below this CDDL HEADER, with the
017 * fields enclosed by brackets "[]" replaced with your own identifying
018 * information:
019 *      Portions Copyright [yyyy] [name of copyright owner]
020 *
021 * CDDL HEADER END
022 *
023 *
024 *      Copyright 2006-2008 Sun Microsystems, Inc.
025 *      Portions copyright 2012-2013 ForgeRock AS.
026 *      Portions Copyright 2014 Manuel Gaupp
027 */
028
029package org.forgerock.opendj.io;
030
031import static com.forgerock.opendj.ldap.CoreMessages.ERR_ASN1_UNEXPECTED_TAG;
032
033import java.io.IOException;
034
035import org.forgerock.i18n.LocalizableMessage;
036import org.forgerock.opendj.ldap.ByteString;
037import org.forgerock.opendj.ldap.ByteStringBuilder;
038import org.forgerock.opendj.ldap.DecodeException;
039
040/**
041 * An abstract {@code ASN1Reader} which can be used as the basis for
042 * implementing new ASN1 reader implementations.
043 */
044public abstract class AbstractASN1Reader implements ASN1Reader {
045    /**
046     * Creates a new abstract ASN.1 reader.
047     */
048    protected AbstractASN1Reader() {
049        // No implementation required.
050    }
051
052    /** {@inheritDoc} */
053    public boolean readBoolean(byte type) throws IOException {
054        if (type == 0x00) {
055            type = ASN1.UNIVERSAL_BOOLEAN_TYPE;
056        }
057        checkType(type);
058        return readBoolean();
059    }
060
061    /** {@inheritDoc} */
062    public int readEnumerated(byte type) throws IOException {
063        if (type == 0x00) {
064            type = ASN1.UNIVERSAL_ENUMERATED_TYPE;
065        }
066        checkType(type);
067        return readEnumerated();
068    }
069
070    /** {@inheritDoc} */
071    public long readInteger(byte type) throws IOException {
072        if (type == 0x00) {
073            type = ASN1.UNIVERSAL_INTEGER_TYPE;
074        }
075        checkType(type);
076        return readInteger();
077    }
078
079    /** {@inheritDoc} */
080    public void readNull(byte type) throws IOException {
081        if (type == 0x00) {
082            type = ASN1.UNIVERSAL_NULL_TYPE;
083        }
084        checkType(type);
085        readNull();
086    }
087
088    /** {@inheritDoc} */
089    public ByteString readOctetString(byte type) throws IOException {
090        if (type == 0x00) {
091            type = ASN1.UNIVERSAL_OCTET_STRING_TYPE;
092        }
093        checkType(type);
094        return readOctetString();
095    }
096
097    /** {@inheritDoc} */
098    public ByteStringBuilder readOctetString(byte type, final ByteStringBuilder builder)
099            throws IOException {
100        if (type == 0x00) {
101            type = ASN1.UNIVERSAL_OCTET_STRING_TYPE;
102        }
103        checkType(type);
104        readOctetString(builder);
105        return builder;
106    }
107
108    /** {@inheritDoc} */
109    public String readOctetStringAsString(byte type) throws IOException {
110        // We could cache the UTF-8 CharSet if performance proves to be an
111        // issue.
112        if (type == 0x00) {
113            type = ASN1.UNIVERSAL_OCTET_STRING_TYPE;
114        }
115        checkType(type);
116        return readOctetStringAsString();
117    }
118
119    /** {@inheritDoc} */
120    public void readStartExplicitTag(byte type) throws IOException {
121        if (type == 0x00) {
122            type = (ASN1.TYPE_MASK_CONTEXT | ASN1.TYPE_MASK_CONSTRUCTED);
123        }
124        checkType(type);
125        readStartExplicitTag();
126    }
127
128    /** {@inheritDoc} */
129    public void readStartSequence(byte type) throws IOException {
130        if (type == 0x00) {
131            type = ASN1.UNIVERSAL_SEQUENCE_TYPE;
132        }
133        checkType(type);
134        readStartSequence();
135    }
136
137    /** {@inheritDoc} */
138    public void readStartSet(byte type) throws IOException {
139        // From an implementation point of view, a set is equivalent to a
140        // sequence.
141        if (type == 0x00) {
142            type = ASN1.UNIVERSAL_SET_TYPE;
143        }
144        checkType(type);
145        readStartSet();
146    }
147
148    /** {@inheritDoc} */
149    public ASN1Reader skipElement(final byte expectedType) throws IOException {
150        if (peekType() != expectedType) {
151            final LocalizableMessage message =
152                    ERR_ASN1_UNEXPECTED_TAG.get(expectedType, peekType());
153            throw DecodeException.fatalError(message);
154        }
155        skipElement();
156        return this;
157    }
158
159    private void checkType(final byte expectedType) throws IOException {
160        if (peekType() != expectedType) {
161            final LocalizableMessage message =
162                    ERR_ASN1_UNEXPECTED_TAG.get(expectedType, peekType());
163            throw DecodeException.fatalError(message);
164        }
165    }
166}