1package org.bouncycastle.asn1;
2
3import java.io.IOException;
4
5/**
6 * DER PrintableString object.
7 */
8public class DERPrintableString
9    extends ASN1Object
10    implements DERString
11{
12    // BEGIN android-changed
13    private final String string;
14    // END android-changed
15
16    /**
17     * return a printable string from the passed in object.
18     *
19     * @exception IllegalArgumentException if the object cannot be converted.
20     */
21    public static DERPrintableString getInstance(
22        Object  obj)
23    {
24        if (obj == null || obj instanceof DERPrintableString)
25        {
26            return (DERPrintableString)obj;
27        }
28
29        throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
30    }
31
32    /**
33     * return a Printable String from a tagged object.
34     *
35     * @param obj the tagged object holding the object we want
36     * @param explicit true if the object is meant to be explicitly
37     *              tagged false otherwise.
38     * @exception IllegalArgumentException if the tagged object cannot
39     *               be converted.
40     */
41    public static DERPrintableString getInstance(
42        ASN1TaggedObject obj,
43        boolean          explicit)
44    {
45        DERObject o = obj.getObject();
46
47        if (explicit || o instanceof DERPrintableString)
48        {
49            return getInstance(o);
50        }
51        else
52        {
53            return new DERPrintableString(ASN1OctetString.getInstance(o).getOctets());
54        }
55    }
56
57    /**
58     * basic constructor - byte encoded string.
59     */
60    public DERPrintableString(
61        byte[]   string)
62    {
63        char[]  cs = new char[string.length];
64
65        for (int i = 0; i != cs.length; i++)
66        {
67            cs[i] = (char)(string[i] & 0xff);
68        }
69
70        // BEGIN android-changed
71        this.string = new String(cs).intern();
72        // END android-changed
73    }
74
75    /**
76     * basic constructor - this does not validate the string
77     */
78    public DERPrintableString(
79        String   string)
80    {
81        this(string, false);
82    }
83
84    /**
85     * Constructor with optional validation.
86     *
87     * @param string the base string to wrap.
88     * @param validate whether or not to check the string.
89     * @throws IllegalArgumentException if validate is true and the string
90     * contains characters that should not be in a PrintableString.
91     */
92    public DERPrintableString(
93        String   string,
94        boolean  validate)
95    {
96        if (validate && !isPrintableString(string))
97        {
98            throw new IllegalArgumentException("string contains illegal characters");
99        }
100
101        // BEGIN android-changed
102        this.string = string.intern();
103        // END android-changed
104    }
105
106    public String getString()
107    {
108        return string;
109    }
110
111    public byte[] getOctets()
112    {
113        char[]  cs = string.toCharArray();
114        byte[]  bs = new byte[cs.length];
115
116        for (int i = 0; i != cs.length; i++)
117        {
118            bs[i] = (byte)cs[i];
119        }
120
121        return bs;
122    }
123
124    void encode(
125        DEROutputStream  out)
126        throws IOException
127    {
128        out.writeEncoded(PRINTABLE_STRING, this.getOctets());
129    }
130
131    public int hashCode()
132    {
133        return this.getString().hashCode();
134    }
135
136    boolean asn1Equals(
137        DERObject  o)
138    {
139        if (!(o instanceof DERPrintableString))
140        {
141            return false;
142        }
143
144        DERPrintableString  s = (DERPrintableString)o;
145
146        return this.getString().equals(s.getString());
147    }
148
149    public String toString()
150    {
151        return string;
152    }
153
154    /**
155     * return true if the passed in String can be represented without
156     * loss as a PrintableString, false otherwise.
157     *
158     * @return true if in printable set, false otherwise.
159     */
160    public static boolean isPrintableString(
161        String  str)
162    {
163        for (int i = str.length() - 1; i >= 0; i--)
164        {
165            char    ch = str.charAt(i);
166
167            if (ch > 0x007f)
168            {
169                return false;
170            }
171
172            if ('a' <= ch && ch <= 'z')
173            {
174                continue;
175            }
176
177            if ('A' <= ch && ch <= 'Z')
178            {
179                continue;
180            }
181
182            if ('0' <= ch && ch <= '9')
183            {
184                continue;
185            }
186
187            switch (ch)
188            {
189            case ' ':
190            case '\'':
191            case '(':
192            case ')':
193            case '+':
194            case '-':
195            case '.':
196            case ':':
197            case '=':
198            case '?':
199            case '/':
200            case ',':
201                continue;
202            }
203
204            return false;
205        }
206
207        return true;
208    }
209}
210