001package org.apache.commons.ssl.org.bouncycastle.asn1; 002 003import java.io.IOException; 004 005import org.bouncycastle.util.Arrays; 006import org.bouncycastle.util.Strings; 007 008/** 009 * DER PrintableString object. 010 */ 011public class DERPrintableString 012 extends ASN1Primitive 013 implements ASN1String 014{ 015 private byte[] string; 016 017 /** 018 * return a printable string from the passed in object. 019 * 020 * @param obj a DERPrintableString or an object that can be converted into one. 021 * @exception IllegalArgumentException if the object cannot be converted. 022 * @return a DERPrintableString instance, or null. 023 */ 024 public static DERPrintableString getInstance( 025 Object obj) 026 { 027 if (obj == null || obj instanceof DERPrintableString) 028 { 029 return (DERPrintableString)obj; 030 } 031 032 if (obj instanceof byte[]) 033 { 034 try 035 { 036 return (DERPrintableString)fromByteArray((byte[])obj); 037 } 038 catch (Exception e) 039 { 040 throw new IllegalArgumentException("encoding error in getInstance: " + e.toString()); 041 } 042 } 043 044 throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); 045 } 046 047 /** 048 * return a Printable String from a tagged object. 049 * 050 * @param obj the tagged object holding the object we want 051 * @param explicit true if the object is meant to be explicitly 052 * tagged false otherwise. 053 * @exception IllegalArgumentException if the tagged object cannot 054 * be converted. 055 * @return a DERPrintableString instance, or null. 056 */ 057 public static DERPrintableString getInstance( 058 ASN1TaggedObject obj, 059 boolean explicit) 060 { 061 ASN1Primitive o = obj.getObject(); 062 063 if (explicit || o instanceof DERPrintableString) 064 { 065 return getInstance(o); 066 } 067 else 068 { 069 return new DERPrintableString(ASN1OctetString.getInstance(o).getOctets()); 070 } 071 } 072 073 /** 074 * basic constructor - byte encoded string. 075 */ 076 DERPrintableString( 077 byte[] string) 078 { 079 this.string = string; 080 } 081 082 /** 083 * basic constructor - this does not validate the string 084 */ 085 public DERPrintableString( 086 String string) 087 { 088 this(string, false); 089 } 090 091 /** 092 * Constructor with optional validation. 093 * 094 * @param string the base string to wrap. 095 * @param validate whether or not to check the string. 096 * @throws IllegalArgumentException if validate is true and the string 097 * contains characters that should not be in a PrintableString. 098 */ 099 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}