001package org.apache.commons.ssl.asn1;
002
003import java.io.IOException;
004
005/** DER PrintableString object. */
006public class DERPrintableString
007    extends ASN1Object
008    implements DERString {
009    String string;
010
011    /**
012     * return a printable string from the passed in object.
013     *
014     * @throws IllegalArgumentException if the object cannot be converted.
015     */
016    public static DERPrintableString getInstance(
017        Object obj) {
018        if (obj == null || obj instanceof DERPrintableString) {
019            return (DERPrintableString) obj;
020        }
021
022        if (obj instanceof ASN1OctetString) {
023            return new DERPrintableString(((ASN1OctetString) obj).getOctets());
024        }
025
026        if (obj instanceof ASN1TaggedObject) {
027            return getInstance(((ASN1TaggedObject) obj).getObject());
028        }
029
030        throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
031    }
032
033    /**
034     * return a Printable String from a tagged object.
035     *
036     * @param obj      the tagged object holding the object we want
037     * @param explicit true if the object is meant to be explicitly
038     *                 tagged false otherwise.
039     * @throws IllegalArgumentException if the tagged object cannot
040     *                                  be converted.
041     */
042    public static DERPrintableString getInstance(
043        ASN1TaggedObject obj,
044        boolean explicit) {
045        return getInstance(obj.getObject());
046    }
047
048    /** basic constructor - byte encoded string. */
049    public DERPrintableString(
050        byte[] string) {
051        char[] cs = new char[string.length];
052
053        for (int i = 0; i != cs.length; i++) {
054            cs[i] = (char) (string[i] & 0xff);
055        }
056
057        this.string = new String(cs);
058    }
059
060    /** basic constructor - this does not validate the string */
061    public DERPrintableString(
062        String string) {
063        this(string, false);
064    }
065
066    /**
067     * Constructor with optional validation.
068     *
069     * @param string   the base string to wrap.
070     * @param validate whether or not to check the string.
071     * @throws IllegalArgumentException if validate is true and the string
072     *                                  contains characters that should not be in a PrintableString.
073     */
074    public DERPrintableString(
075        String string,
076        boolean validate) {
077        if (validate && !isPrintableString(string)) {
078            throw new IllegalArgumentException("string contains illegal characters");
079        }
080
081        this.string = string;
082    }
083
084    public String getString() {
085        return string;
086    }
087
088    public byte[] getOctets() {
089        char[] cs = string.toCharArray();
090        byte[] bs = new byte[cs.length];
091
092        for (int i = 0; i != cs.length; i++) {
093            bs[i] = (byte) cs[i];
094        }
095
096        return bs;
097    }
098
099    void encode(
100        DEROutputStream out)
101        throws IOException {
102        out.writeEncoded(PRINTABLE_STRING, this.getOctets());
103    }
104
105    public int hashCode() {
106        return this.getString().hashCode();
107    }
108
109    boolean asn1Equals(
110        DERObject o) {
111        if (!(o instanceof DERPrintableString)) {
112            return false;
113        }
114
115        DERPrintableString s = (DERPrintableString) o;
116
117        return this.getString().equals(s.getString());
118    }
119
120    public String toString() {
121        return string;
122    }
123
124    /**
125     * return true if the passed in String can be represented without
126     * loss as a PrintableString, false otherwise.
127     *
128     * @return true if in printable set, false otherwise.
129     */
130    public static boolean isPrintableString(
131        String str) {
132        for (int i = str.length() - 1; i >= 0; i--) {
133            char ch = str.charAt(i);
134
135            if (ch > 0x007f) {
136                return false;
137            }
138
139            if ('a' <= ch && ch <= 'z') {
140                continue;
141            }
142
143            if ('A' <= ch && ch <= 'Z') {
144                continue;
145            }
146
147            if ('0' <= ch && ch <= '9') {
148                continue;
149            }
150
151            switch (ch) {
152                case ' ':
153                case '\'':
154                case '(':
155                case ')':
156                case '+':
157                case '-':
158                case '.':
159                case ':':
160                case '=':
161                case '?':
162                case '/':
163                case ',':
164                    continue;
165            }
166
167            return false;
168        }
169
170        return true;
171    }
172}