001package org.apache.commons.ssl.org.bouncycastle.asn1;
002
003import java.io.IOException;
004
005import org.bouncycastle.util.Arrays;
006import org.bouncycastle.util.Strings;
007
008/**
009 * DER NumericString object - this is an ascii string of characters {0,1,2,3,4,5,6,7,8,9, }.
010 */
011public class DERNumericString
012    extends ASN1Primitive
013    implements ASN1String
014{
015    private byte[]  string;
016
017    /**
018     * return a Numeric string from the passed in object
019     *
020     * @param obj a DERNumericString or an object that can be converted into one.
021     * @exception IllegalArgumentException if the object cannot be converted.
022     * @return a DERNumericString instance, or null
023     */
024    public static DERNumericString getInstance(
025        Object  obj)
026    {
027        if (obj == null || obj instanceof DERNumericString)
028        {
029            return (DERNumericString)obj;
030        }
031
032        if (obj instanceof byte[])
033        {
034            try
035            {
036                return (DERNumericString)fromByteArray((byte[])obj);
037            }
038            catch (Exception e)
039            {
040                throw new IllegalArgumentException("encoding error in getInstance: " + e.toString());
041            }
042        }
043
044        throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
045    }
046
047    /**
048     * return an Numeric String from a tagged object.
049     *
050     * @param obj the tagged object holding the object we want
051     * @param explicit true if the object is meant to be explicitly
052     *              tagged false otherwise.
053     * @exception IllegalArgumentException if the tagged object cannot
054     *               be converted.
055     * @return a DERNumericString instance, or null.
056     */
057    public static DERNumericString getInstance(
058        ASN1TaggedObject obj,
059        boolean          explicit)
060    {
061        ASN1Primitive o = obj.getObject();
062
063        if (explicit || o instanceof DERNumericString)
064        {
065            return getInstance(o);
066        }
067        else
068        {
069            return new DERNumericString(ASN1OctetString.getInstance(o).getOctets());
070        }
071    }
072
073    /**
074     * basic constructor - with bytes.
075     */
076    DERNumericString(
077        byte[]   string)
078    {
079        this.string = string;
080    }
081
082    /**
083     * basic constructor -  without validation..
084     */
085    public DERNumericString(
086        String   string)
087    {
088        this(string, false);
089    }
090
091    /**
092     * Constructor with optional validation.
093     *
094     * @param string the base string to wrap.
095     * @param validate whether or not to check the string.
096     * @throws IllegalArgumentException if validate is true and the string
097     * contains characters that should not be in a NumericString.
098     */
099    public DERNumericString(
100        String   string,
101        boolean  validate)
102    {
103        if (validate && !isNumericString(string))
104        {
105            throw new IllegalArgumentException("string contains illegal characters");
106        }
107
108        this.string = Strings.toByteArray(string);
109    }
110
111    public String getString()
112    {
113        return Strings.fromByteArray(string);
114    }
115
116    public String toString()
117    {
118        return getString();
119    }
120
121    public byte[] getOctets()
122    {
123        return Arrays.clone(string);
124    }
125
126    boolean isConstructed()
127    {
128        return false;
129    }
130
131    int encodedLength()
132    {
133        return 1 + StreamUtil.calculateBodyLength(string.length) + string.length;
134    }
135
136    void encode(
137        ASN1OutputStream out)
138        throws IOException
139    {
140        out.writeEncoded(BERTags.NUMERIC_STRING, string);
141    }
142
143    public int hashCode()
144    {
145        return Arrays.hashCode(string);
146    }
147
148    boolean asn1Equals(
149        ASN1Primitive o)
150    {
151        if (!(o instanceof DERNumericString))
152        {
153            return false;
154        }
155
156        DERNumericString  s = (DERNumericString)o;
157
158        return Arrays.areEqual(string, s.string);
159    }
160
161    /**
162     * Return true if the string can be represented as a NumericString ('0'..'9', ' ')
163     *
164     * @param str string to validate.
165     * @return true if numeric, fale otherwise.
166     */
167    public static boolean isNumericString(
168        String  str)
169    {
170        for (int i = str.length() - 1; i >= 0; i--)
171        {
172            char    ch = str.charAt(i);
173
174            if (ch > 0x007f)
175            {
176                return false;
177            }
178
179            if (('0' <= ch && ch <= '9') || ch == ' ')
180            {
181                continue;
182            }
183
184            return false;
185        }
186
187        return true;
188    }
189}