1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17
18/**
19* @author Vladimir N. Molotkov, Stepan M. Mishura
20* @version $Revision$
21*/
22
23package org.apache.harmony.security.asn1;
24
25import java.io.IOException;
26import java.io.InputStream;
27
28
29/**
30 * This abstract class is the super class for all ASN.1 types
31 *
32 * @see <a href="http://asn1.elibel.tm.fr/en/standards/index.htm">ASN.1</a>
33 */
34public abstract class ASN1Type implements ASN1Constants {
35
36    /** Integer representation of primitive identifier. */
37    public final int id;
38
39    /** Integer representation of constructed identifier. */
40    public final int constrId;
41
42    /**
43     * Constructs a primitive, universal ASN.1 type.
44     *
45     * @param tagNumber - ASN.1 tag number
46     * @throws IllegalArgumentException - if tagNumber is invalid
47     */
48    public ASN1Type(int tagNumber) {
49        this(CLASS_UNIVERSAL, tagNumber);
50    }
51
52    /**
53     * Constructs an ASN.1 type.
54     *
55     * @param tagClass - tag class. MUST be
56     *     CLASS_UNIVERSAL, CLASS_APPLICATION, CLASS_CONTEXTSPECIFIC, CLASS_PRIVATE
57     * @param tagNumber - ASN.1 tag number.
58     * @throws IllegalArgumentException - if tagClass or tagNumber is invalid
59     */
60    public ASN1Type(int tagClass, int tagNumber) {
61        if (tagNumber < 0) {
62            throw new IllegalArgumentException("tagNumber < 0");
63        }
64
65        if (tagClass != CLASS_UNIVERSAL && tagClass != CLASS_APPLICATION
66                && tagClass != CLASS_CONTEXTSPECIFIC
67                && tagClass != CLASS_PRIVATE) {
68            throw new IllegalArgumentException("invalid tagClass");
69        }
70
71        if (tagNumber < 31) {
72            // short form
73            this.id = tagClass + tagNumber;
74        } else {
75            // long form
76            throw new IllegalArgumentException("tag long form not implemented");
77        }
78        this.constrId = this.id + PC_CONSTRUCTED;
79    }
80
81    public final Object decode(byte[] encoded) throws IOException {
82        return decode(new DerInputStream(encoded));
83    }
84
85    public final Object decode(byte[] encoded, int offset, int encodingLen)
86            throws IOException {
87        return decode(new DerInputStream(encoded, offset, encodingLen));
88    }
89
90    public final Object decode(InputStream in) throws IOException {
91        return decode(new DerInputStream(in));
92    }
93
94    public final void verify(byte[] encoded) throws IOException {
95        DerInputStream decoder = new DerInputStream(encoded);
96        decoder.setVerify();
97        decode(decoder);
98    }
99
100    public final void verify(InputStream in) throws IOException {
101        DerInputStream decoder = new DerInputStream(in);
102        decoder.setVerify();
103        decode(decoder);
104    }
105
106    public final byte[] encode(Object object) {
107        DerOutputStream out = new DerOutputStream(this, object);
108        return out.encoded;
109    }
110
111    /**
112     * Decodes ASN.1 type.
113     *
114     * @throws IOException if an I/O error occurs or the end of the stream is reached
115     */
116    public abstract Object decode(BerInputStream in) throws IOException;
117
118    /**
119     * Tests provided identifier.
120     *
121     * @param identifier identifier to be verified
122     * @return true if identifier is associated with this ASN.1 type
123     */
124    public abstract boolean checkTag(int identifier);
125
126    /**
127     * Creates decoded object.
128     *
129     * Derived classes should override this method to provide creation for a
130     * selected class of objects during decoding.
131     *
132     * The default implementation returns an object created by decoding stream.
133     */
134    protected Object getDecodedObject(BerInputStream in) throws IOException {
135        return in.content;
136    }
137
138    /**
139     * Encodes ASN.1 type.
140     */
141    public abstract void encodeASN(BerOutputStream out);
142
143    public abstract void encodeContent(BerOutputStream out);
144
145    public abstract void setEncodingContent(BerOutputStream out);
146
147    public int getEncodedLength(BerOutputStream out) { //FIXME name
148        //tag length
149        int len = 1; //FIXME tag length = 1. what about long form?
150        //for (; tag > 0; tag = tag >> 8, len++);
151
152        // length length :-)
153        len++;
154        if (out.length > 127) {
155
156            len++;
157            for (int cur = out.length >> 8; cur > 0; len++) {
158                cur = cur >> 8;
159            }
160        }
161        len += out.length;
162
163        return len;
164    }
165
166    @Override public String toString() {
167        // TODO decide whether this method is necessary
168        return getClass().getName() + "(tag: 0x" + Integer.toHexString(0xff & this.id) + ")";
169    }
170}
171