    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}