1 package org.bouncycastle.asn1; 2 3 import java.io.IOException; 4 5 /** 6 * DER PrintableString object. 7 */ 8 public 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