1package org.bouncycastle.asn1;
2
3import java.io.IOException;
4
5import org.bouncycastle.util.Arrays;
6import org.bouncycastle.util.Strings;
7
8/**
9 * DER IA5String object - this is an ascii string.
10 */
11public class DERIA5String
12    extends ASN1Primitive
13    implements ASN1String
14{
15    private final byte[]  string;
16
17    /**
18     * return a IA5 string from the passed in object
19     *
20     * @param obj a DERIA5String or an object that can be converted into one.
21     * @exception IllegalArgumentException if the object cannot be converted.
22     * @return a DERIA5String instance, or null.
23     */
24    public static DERIA5String getInstance(
25        Object  obj)
26    {
27        if (obj == null || obj instanceof DERIA5String)
28        {
29            return (DERIA5String)obj;
30        }
31
32        if (obj instanceof byte[])
33        {
34            try
35            {
36                return (DERIA5String)fromByteArray((byte[])obj);
37            }
38            catch (Exception e)
39            {
40                throw new IllegalArgumentException("encoding error in getInstance: " + e.toString());
41            }
42        }
43
44        throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
45    }
46
47    /**
48     * return an IA5 String from a tagged object.
49     *
50     * @param obj the tagged object holding the object we want
51     * @param explicit true if the object is meant to be explicitly
52     *              tagged false otherwise.
53     * @exception IllegalArgumentException if the tagged object cannot
54     *               be converted.
55     * @return a DERIA5String instance, or null.
56     */
57    public static DERIA5String getInstance(
58        ASN1TaggedObject obj,
59        boolean          explicit)
60    {
61        ASN1Primitive o = obj.getObject();
62
63        if (explicit || o instanceof DERIA5String)
64        {
65            return getInstance(o);
66        }
67        else
68        {
69            return new DERIA5String(((ASN1OctetString)o).getOctets());
70        }
71    }
72
73    /**
74     * basic constructor - with bytes.
75     * @param string the byte encoding of the characters making up the string.
76     */
77    DERIA5String(
78        byte[]   string)
79    {
80        this.string = string;
81    }
82
83    /**
84     * basic constructor - without validation.
85     * @param string the base string to use..
86     */
87    public DERIA5String(
88        String   string)
89    {
90        this(string, false);
91    }
92
93    /**
94     * Constructor with optional validation.
95     *
96     * @param string the base string to wrap.
97     * @param validate whether or not to check the string.
98     * @throws IllegalArgumentException if validate is true and the string
99     * 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}
190