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 PrintableString object.
010 */
011public class DERPrintableString
012    extends ASN1Primitive
013    implements ASN1String
014{
015    private byte[]  string;
016
017    /**
018     * return a printable string from the passed in object.
019     *
020     * @param obj a DERPrintableString or an object that can be converted into one.
021     * @exception IllegalArgumentException if the object cannot be converted.
022     * @return a DERPrintableString instance, or null.
023     */
024    public static DERPrintableString getInstance(
025        Object  obj)
026    {
027        if (obj == null || obj instanceof DERPrintableString)
028        {
029            return (DERPrintableString)obj;
030        }
031
032        if (obj instanceof byte[])
033        {
034            try
035            {
036                return (DERPrintableString)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 a Printable 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 DERPrintableString instance, or null.
056     */
057    public static DERPrintableString getInstance(
058        ASN1TaggedObject obj,
059        boolean          explicit)
060    {
061        ASN1Primitive o = obj.getObject();
062
063        if (explicit || o instanceof DERPrintableString)
064        {
065            return getInstance(o);
066        }
067        else
068        {
069            return new DERPrintableString(ASN1OctetString.getInstance(o).getOctets());
070        }
071    }
072
073    /**
074     * basic constructor - byte encoded string.
075     */
076    DERPrintableString(
077        byte[]   string)
078    {
079        this.string = string;
080    }
081
082    /**
083     * basic constructor - this does not validate the string
084     */
085    public DERPrintableString(
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 PrintableString.
098     */
099    public DERPrintableString(
100        String   string,
101        boolean  validate)
102    {
103        if (validate && !isPrintableString(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 byte[] getOctets()
117    {
118        return Arrays.clone(string);
119    }
120
121    boolean isConstructed()
122    {
123        return false;
124    }
125
126    int encodedLength()
127    {
128        return 1 + StreamUtil.calculateBodyLength(string.length) + string.length;
129    }
130
131    void encode(
132        ASN1OutputStream out)
133        throws IOException
134    {
135        out.writeEncoded(BERTags.PRINTABLE_STRING, string);
136    }
137
138    public int hashCode()
139    {
140        return Arrays.hashCode(string);
141    }
142
143    boolean asn1Equals(
144        ASN1Primitive o)
145    {
146        if (!(o instanceof DERPrintableString))
147        {
148            return false;
149        }
150
151        DERPrintableString  s = (DERPrintableString)o;
152
153        return Arrays.areEqual(string, s.string);
154    }
155
156    public String toString()
157    {
158        return getString();
159    }
160
161    /**
162     * return true if the passed in String can be represented without
163     * loss as a PrintableString, false otherwise.
164     *
165     * @return true if in printable set, false otherwise.
166     */
167    public static boolean isPrintableString(
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 ('a' <= ch && ch <= 'z')
180            {
181                continue;
182            }
183
184            if ('A' <= ch && ch <= 'Z')
185            {
186                continue;
187            }
188
189            if ('0' <= ch && ch <= '9')
190            {
191                continue;
192            }
193
194            switch (ch)
195            {
196            case ' ':
197            case '\'':
198            case '(':
199            case ')':
200            case '+':
201            case '-':
202            case '.':
203            case ':':
204            case '=':
205            case '?':
206            case '/':
207            case ',':
208                continue;
209            }
210
211            return false;
212        }
213
214        return true;
215    }
216}