1package org.bouncycastle.asn1; 2 3import java.io.IOException; 4 5import org.bouncycastle.util.Arrays; 6import org.bouncycastle.util.Strings; 7 8/** 9 * DER PrintableString object. 10 */ 11public class DERPrintableString 12 extends ASN1Primitive 13 implements ASN1String 14{ 15 // BEGIN android-changed 16 private final byte[] string; 17 // END android-changed 18 19 /** 20 * return a printable string from the passed in object. 21 * 22 * @exception IllegalArgumentException if the object cannot be converted. 23 */ 24 public static DERPrintableString getInstance( 25 Object obj) 26 { 27 if (obj == null || obj instanceof DERPrintableString) 28 { 29 return (DERPrintableString)obj; 30 } 31 32 if (obj instanceof byte[]) 33 { 34 try 35 { 36 return (DERPrintableString)fromByteArray((byte[])obj); 37 } 38 catch (Exception e) 39 { 40 throw new IllegalArgumentException("encoding error in getInstance: " + e.toString()); 41 } 42 } 43 44 throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); 45 } 46 47 /** 48 * return a Printable String from a tagged object. 49 * 50 * @param obj the tagged object holding the object we want 51 * @param explicit true if the object is meant to be explicitly 52 * tagged false otherwise. 53 * @exception IllegalArgumentException if the tagged object cannot 54 * be converted. 55 */ 56 public static DERPrintableString getInstance( 57 ASN1TaggedObject obj, 58 boolean explicit) 59 { 60 ASN1Primitive o = obj.getObject(); 61 62 if (explicit || o instanceof DERPrintableString) 63 { 64 return getInstance(o); 65 } 66 else 67 { 68 return new DERPrintableString(ASN1OctetString.getInstance(o).getOctets()); 69 } 70 } 71 72 /** 73 * basic constructor - byte encoded string. 74 */ 75 DERPrintableString( 76 byte[] string) 77 { 78 this.string = string; 79 } 80 81 /** 82 * basic constructor - this does not validate the string 83 */ 84 public DERPrintableString( 85 String string) 86 { 87 this(string, false); 88 } 89 90 /** 91 * Constructor with optional validation. 92 * 93 * @param string the base string to wrap. 94 * @param validate whether or not to check the string. 95 * @throws IllegalArgumentException if validate is true and the string 96 * contains characters that should not be in a PrintableString. 97 */ 98 public DERPrintableString( 99 String string, 100 boolean validate) 101 { 102 if (validate && !isPrintableString(string)) 103 { 104 throw new IllegalArgumentException("string contains illegal characters"); 105 } 106 107 this.string = Strings.toByteArray(string); 108 } 109 110 public String getString() 111 { 112 return Strings.fromByteArray(string); 113 } 114 115 public byte[] getOctets() 116 { 117 return Arrays.clone(string); 118 } 119 120 boolean isConstructed() 121 { 122 return false; 123 } 124 125 int encodedLength() 126 { 127 return 1 + StreamUtil.calculateBodyLength(string.length) + string.length; 128 } 129 130 void encode( 131 ASN1OutputStream out) 132 throws IOException 133 { 134 out.writeEncoded(BERTags.PRINTABLE_STRING, string); 135 } 136 137 public int hashCode() 138 { 139 return Arrays.hashCode(string); 140 } 141 142 boolean asn1Equals( 143 ASN1Primitive o) 144 { 145 if (!(o instanceof DERPrintableString)) 146 { 147 return false; 148 } 149 150 DERPrintableString s = (DERPrintableString)o; 151 152 return Arrays.areEqual(string, s.string); 153 } 154 155 public String toString() 156 { 157 return getString(); 158 } 159 160 /** 161 * return true if the passed in String can be represented without 162 * loss as a PrintableString, false otherwise. 163 * 164 * @return true if in printable set, false otherwise. 165 */ 166 public static boolean isPrintableString( 167 String str) 168 { 169 for (int i = str.length() - 1; i >= 0; i--) 170 { 171 char ch = str.charAt(i); 172 173 if (ch > 0x007f) 174 { 175 return false; 176 } 177 178 if ('a' <= ch && ch <= 'z') 179 { 180 continue; 181 } 182 183 if ('A' <= ch && ch <= 'Z') 184 { 185 continue; 186 } 187 188 if ('0' <= ch && ch <= '9') 189 { 190 continue; 191 } 192 193 switch (ch) 194 { 195 case ' ': 196 case '\'': 197 case '(': 198 case ')': 199 case '+': 200 case '-': 201 case '.': 202 case ':': 203 case '=': 204 case '?': 205 case '/': 206 case ',': 207 continue; 208 } 209 210 return false; 211 } 212 213 return true; 214 } 215} 216