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 private final byte[] string; 16 17 /** 18 * return a printable string from the passed in object. 19 * 20 * @param obj a DERPrintableString or an object that can be converted into one. 21 * @exception IllegalArgumentException if the object cannot be converted. 22 * @return a DERPrintableString instance, or null. 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 * @return a DERPrintableString instance, or null. 56 */ 57 public static DERPrintableString getInstance( 58 ASN1TaggedObject obj, 59 boolean explicit) 60 { 61 ASN1Primitive o = obj.getObject(); 62 63 if (explicit || o instanceof DERPrintableString) 64 { 65 return getInstance(o); 66 } 67 else 68 { 69 return new DERPrintableString(ASN1OctetString.getInstance(o).getOctets()); 70 } 71 } 72 73 /** 74 * basic constructor - byte encoded string. 75 */ 76 DERPrintableString( 77 byte[] string) 78 { 79 this.string = string; 80 } 81 82 /** 83 * basic constructor - this does not validate the string 84 */ 85 public DERPrintableString( 86 String string) 87 { 88 this(string, false); 89 } 90 91 /** 92 * Constructor with optional validation. 93 * 94 * @param string the base string to wrap. 95 * @param validate whether or not to check the string. 96 * @throws IllegalArgumentException if validate is true and the string 97 * contains characters that should not be in a PrintableString. 98 */ 99 public DERPrintableString( 100 String string, 101 boolean validate) 102 { 103 if (validate && !isPrintableString(string)) 104 { 105 throw new IllegalArgumentException("string contains illegal characters"); 106 } 107 108 this.string = Strings.toByteArray(string); 109 } 110 111 public String getString() 112 { 113 return Strings.fromByteArray(string); 114 } 115 116 public byte[] getOctets() 117 { 118 return Arrays.clone(string); 119 } 120 121 boolean isConstructed() 122 { 123 return false; 124 } 125 126 int encodedLength() 127 { 128 return 1 + StreamUtil.calculateBodyLength(string.length) + string.length; 129 } 130 131 void encode( 132 ASN1OutputStream out) 133 throws IOException 134 { 135 out.writeEncoded(BERTags.PRINTABLE_STRING, string); 136 } 137 138 public int hashCode() 139 { 140 return Arrays.hashCode(string); 141 } 142 143 boolean asn1Equals( 144 ASN1Primitive o) 145 { 146 if (!(o instanceof DERPrintableString)) 147 { 148 return false; 149 } 150 151 DERPrintableString s = (DERPrintableString)o; 152 153 return Arrays.areEqual(string, s.string); 154 } 155 156 public String toString() 157 { 158 return getString(); 159 } 160 161 /** 162 * return true if the passed in String can be represented without 163 * loss as a PrintableString, false otherwise. 164 * 165 * @return true if in printable set, false otherwise. 166 */ 167 public static boolean isPrintableString( 168 String str) 169 { 170 for (int i = str.length() - 1; i >= 0; i--) 171 { 172 char ch = str.charAt(i); 173 174 if (ch > 0x007f) 175 { 176 return false; 177 } 178 179 if ('a' <= ch && ch <= 'z') 180 { 181 continue; 182 } 183 184 if ('A' <= ch && ch <= 'Z') 185 { 186 continue; 187 } 188 189 if ('0' <= ch && ch <= '9') 190 { 191 continue; 192 } 193 194 switch (ch) 195 { 196 case ' ': 197 case '\'': 198 case '(': 199 case ')': 200 case '+': 201 case '-': 202 case '.': 203 case ':': 204 case '=': 205 case '?': 206 case '/': 207 case ',': 208 continue; 209 } 210 211 return false; 212 } 213 214 return true; 215 } 216} 217