001package org.apache.commons.ssl.asn1;
002
003import java.io.IOException;
004
005/** DER NumericString object - this is an ascii string of characters {0,1,2,3,4,5,6,7,8,9, }. */
006public class DERNumericString
007    extends ASN1Object
008    implements DERString {
009    String string;
010
011    /**
012     * return a Numeric string from the passed in object
013     *
014     * @throws IllegalArgumentException if the object cannot be converted.
015     */
016    public static DERNumericString getInstance(
017        Object obj) {
018        if (obj == null || obj instanceof DERNumericString) {
019            return (DERNumericString) obj;
020        }
021
022        if (obj instanceof ASN1OctetString) {
023            return new DERNumericString(((ASN1OctetString) obj).getOctets());
024        }
025
026        if (obj instanceof ASN1TaggedObject) {
027            return getInstance(((ASN1TaggedObject) obj).getObject());
028        }
029
030        throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
031    }
032
033    /**
034     * return an Numeric String from a tagged object.
035     *
036     * @param obj      the tagged object holding the object we want
037     * @param explicit true if the object is meant to be explicitly
038     *                 tagged false otherwise.
039     * @throws IllegalArgumentException if the tagged object cannot
040     *                                  be converted.
041     */
042    public static DERNumericString getInstance(
043        ASN1TaggedObject obj,
044        boolean explicit) {
045        return getInstance(obj.getObject());
046    }
047
048    /** basic constructor - with bytes. */
049    public DERNumericString(
050        byte[] string) {
051        char[] cs = new char[string.length];
052
053        for (int i = 0; i != cs.length; i++) {
054            cs[i] = (char) (string[i] & 0xff);
055        }
056
057        this.string = new String(cs);
058    }
059
060    /** basic constructor -  without validation.. */
061    public DERNumericString(
062        String string) {
063        this(string, false);
064    }
065
066    /**
067     * Constructor with optional validation.
068     *
069     * @param string   the base string to wrap.
070     * @param validate whether or not to check the string.
071     * @throws IllegalArgumentException if validate is true and the string
072     *                                  contains characters that should not be in a NumericString.
073     */
074    public DERNumericString(
075        String string,
076        boolean validate) {
077        if (validate && !isNumericString(string)) {
078            throw new IllegalArgumentException("string contains illegal characters");
079        }
080
081        this.string = string;
082    }
083
084    public String getString() {
085        return string;
086    }
087
088    public String toString() {
089        return string;
090    }
091
092    public byte[] getOctets() {
093        char[] cs = string.toCharArray();
094        byte[] bs = new byte[cs.length];
095
096        for (int i = 0; i != cs.length; i++) {
097            bs[i] = (byte) cs[i];
098        }
099
100        return bs;
101    }
102
103    void encode(
104        DEROutputStream out)
105        throws IOException {
106        out.writeEncoded(NUMERIC_STRING, this.getOctets());
107    }
108
109    public int hashCode() {
110        return this.getString().hashCode();
111    }
112
113    boolean asn1Equals(
114        DERObject o) {
115        if (!(o instanceof DERNumericString)) {
116            return false;
117        }
118
119        DERNumericString s = (DERNumericString) o;
120
121        return this.getString().equals(s.getString());
122    }
123
124    /**
125     * Return true if the string can be represented as a NumericString ('0'..'9', ' ')
126     *
127     * @param str string to validate.
128     * @return true if numeric, fale otherwise.
129     */
130    public static boolean isNumericString(
131        String str) {
132        for (int i = str.length() - 1; i >= 0; i--) {
133            char ch = str.charAt(i);
134
135            if (ch > 0x007f) {
136                return false;
137            }
138
139            if (('0' <= ch && ch <= '9') || ch == ' ') {
140                continue;
141            }
142
143            return false;
144        }
145
146        return true;
147    }
148}