    001package org.apache.commons.ssl.asn1;
    002
    003import java.io.ByteArrayOutputStream;
    004import java.io.IOException;
    005
    006/** Base class for an application specific object */
    007public class DERApplicationSpecific
    008    extends ASN1Object {
    009    private int tag;
    010    private byte[] octets;
    011
    012    public DERApplicationSpecific(
    013        int tag,
    014        byte[] octets) {
    015        this.tag = tag;
    016        this.octets = octets;
    017    }
    018
    019    public DERApplicationSpecific(
    020        int tag,
    021        DEREncodable object)
    022        throws IOException {
    023        this(true, tag, object);
    024    }
    025
    026    public DERApplicationSpecific(
    027        boolean explicit,
    028        int tag,
    029        DEREncodable object)
    030        throws IOException {
    031        ByteArrayOutputStream bOut = new ByteArrayOutputStream();
    032        DEROutputStream dos = new DEROutputStream(bOut);
    033
    034        dos.writeObject(object);
    035
    036        byte[] data = bOut.toByteArray();
    037
    038        if (tag >= 0x1f) {
    039            throw new IOException("unsupported tag number");
    040        }
    041
    042        if (explicit) {
    043            this.tag = tag | DERTags.CONSTRUCTED;
    044            this.octets = data;
    045        } else {
    046            this.tag = tag;
    047            int lenBytes = getLengthOfLength(data);
    048            byte[] tmp = new byte[data.length - lenBytes];
    049            System.arraycopy(data, lenBytes, tmp, 0, tmp.length);
    050            this.octets = tmp;
    051        }
    052    }
    053
    054    private int getLengthOfLength(byte[] data) {
    055        int count = 2;               // TODO: assumes only a 1 byte tag number
    056
    057        while ((data[count - 1] & 0x80) != 0) {
    058            count++;
    059        }
    060
    061        return count;
    062    }
    063
    064    public boolean isConstructed() {
    065        return (tag & DERTags.CONSTRUCTED) != 0;
    066    }
    067
    068    public byte[] getContents() {
    069        return octets;
    070    }
    071
    072    public int getApplicationTag() {
    073        return tag;
    074    }
    075
    076    public DERObject getObject()
    077        throws IOException {
    078        return new ASN1InputStream(getContents()).readObject();
    079    }
    080
    081    /**
    082     * Return the enclosed object assuming implicit tagging.
    083     *
    084     * @param derTagNo the type tag that should be applied to the object's contents.
    085     * @return the resulting object
    086     * @throws IOException if reconstruction fails.
    087     */
    088    public DERObject getObject(int derTagNo)
    089        throws IOException {
    090        if (tag >= 0x1f) {
    091            throw new IOException("unsupported tag number");
    092        }
    093
    094        byte[] tmp = this.getEncoded();
    095
    096        tmp[0] = (byte) derTagNo;
    097
    098        return new ASN1InputStream(tmp).readObject();
    099    }
    100
    101    /* (non-Javadoc)
    102    * @see org.apache.commons.ssl.asn1.DERObject#encode(org.apache.commons.ssl.asn1.DEROutputStream)
    103    */
    104    void encode(DEROutputStream out) throws IOException {
    105        out.writeEncoded(DERTags.APPLICATION | tag, octets);
    106    }
    107
    108    boolean asn1Equals(
    109        DERObject o) {
    110        if (!(o instanceof DERApplicationSpecific)) {
    111            return false;
    112        }
    113
    114        DERApplicationSpecific other = (DERApplicationSpecific) o;
    115
    116        if (tag != other.tag) {
    117            return false;
    118        }
    119
    120        if (octets.length != other.octets.length) {
    121            return false;
    122        }
    123
    124        for (int i = 0; i < octets.length; i++) {
    125            if (octets[i] != other.octets[i]) {
    126                return false;
    127            }
    128        }
    129
    130        return true;
    131    }
    132
    133    public int hashCode() {
    134        byte[] b = this.getContents();
    135        int value = 0;
    136
    137        for (int i = 0; i != b.length; i++) {
    138            value ^= (b[i] & 0xff) << (i % 4);
    139        }
    140
    141        return value ^ this.getApplicationTag();
    142    }
    143}