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 IA5String object - this is an ascii string.
010 */
011public class DERIA5String
012    extends ASN1Primitive
013    implements ASN1String
014{
015    private byte[]  string;
016
017    /**
018     * return a IA5 string from the passed in object
019     *
020     * @param obj a DERIA5String or an object that can be converted into one.
021     * @exception IllegalArgumentException if the object cannot be converted.
022     * @return a DERIA5String instance, or null.
023     */
024    public static DERIA5String getInstance(
025        Object  obj)
026    {
027        if (obj == null || obj instanceof DERIA5String)
028        {
029            return (DERIA5String)obj;
030        }
031
032        if (obj instanceof byte[])
033        {
034            try
035            {
036                return (DERIA5String)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 IA5 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 DERIA5String instance, or null.
056     */
057    public static DERIA5String getInstance(
058        ASN1TaggedObject obj,
059        boolean          explicit)
060    {
061        ASN1Primitive o = obj.getObject();
062
063        if (explicit || o instanceof DERIA5String)
064        {
065            return getInstance(o);
066        }
067        else
068        {
069            return new DERIA5String(((ASN1OctetString)o).getOctets());
070        }
071    }
072
073    /**
074     * basic constructor - with bytes.
075     * @param string the byte encoding of the characters making up the string.
076     */
077    DERIA5String(
078        byte[]   string)
079    {
080        this.string = string;
081    }
082
083    /**
084     * basic constructor - without validation.
085     * @param string the base string to use..
086     */
087    public DERIA5String(
088        String   string)
089    {
090        this(string, false);
091    }
092
093    /**
094     * Constructor with optional validation.
095     *
096     * @param string the base string to wrap.
097     * @param validate whether or not to check the string.
098     * @throws IllegalArgumentException if validate is true and the string
099     * contains characters that should not be in an IA5String.
100     */
101    public DERIA5String(
102        String   string,
103        boolean  validate)
104    {
105        if (string == null)
106        {
107            throw new NullPointerException("string cannot be null");
108        }
109        if (validate && !isIA5String(string))
110        {
111            throw new IllegalArgumentException("string contains illegal characters");
112        }
113
114        this.string = Strings.toByteArray(string);
115    }
116
117    public String getString()
118    {
119        return Strings.fromByteArray(string);
120    }
121
122    public String toString()
123    {
124        return getString();
125    }
126
127    public byte[] getOctets()
128    {
129        return Arrays.clone(string);
130    }
131
132    boolean isConstructed()
133    {
134        return false;
135    }
136
137    int encodedLength()
138    {
139        return 1 + StreamUtil.calculateBodyLength(string.length) + string.length;
140    }
141
142    void encode(
143        ASN1OutputStream out)
144        throws IOException
145    {
146        out.writeEncoded(BERTags.IA5_STRING, string);
147    }
148
149    public int hashCode()
150    {
151        return Arrays.hashCode(string);
152    }
153
154    boolean asn1Equals(
155        ASN1Primitive o)
156    {
157        if (!(o instanceof DERIA5String))
158        {
159            return false;
160        }
161
162        DERIA5String  s = (DERIA5String)o;
163
164        return Arrays.areEqual(string, s.string);
165    }
166
167    /**
168     * return true if the passed in String can be represented without
169     * loss as an IA5String, false otherwise.
170     *
171     * @param str the string to check.
172     * @return true if character set in IA5String set, false otherwise.
173     */
174    public static boolean isIA5String(
175        String  str)
176    {
177        for (int i = str.length() - 1; i >= 0; i--)
178        {
179            char    ch = str.charAt(i);
180
181            if (ch > 0x007f)
182            {
183                return false;
184            }
185        }
186
187        return true;
188    }
189}