001 package org.apache.commons.ssl.asn1;
002
003 import java.io.IOException;
004
005 /** DER PrintableString object. */
006 public 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 }