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 NumericString object - this is an ascii string of characters {0,1,2,3,4,5,6,7,8,9, }. 010 */ 011public class DERNumericString 012 extends ASN1Primitive 013 implements ASN1String 014{ 015 private byte[] string; 016 017 /** 018 * return a Numeric string from the passed in object 019 * 020 * @param obj a DERNumericString or an object that can be converted into one. 021 * @exception IllegalArgumentException if the object cannot be converted. 022 * @return a DERNumericString instance, or null 023 */ 024 public static DERNumericString getInstance( 025 Object obj) 026 { 027 if (obj == null || obj instanceof DERNumericString) 028 { 029 return (DERNumericString)obj; 030 } 031 032 if (obj instanceof byte[]) 033 { 034 try 035 { 036 return (DERNumericString)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 an Numeric 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 DERNumericString instance, or null. 056 */ 057 public static DERNumericString getInstance( 058 ASN1TaggedObject obj, 059 boolean explicit) 060 { 061 ASN1Primitive o = obj.getObject(); 062 063 if (explicit || o instanceof DERNumericString) 064 { 065 return getInstance(o); 066 } 067 else 068 { 069 return new DERNumericString(ASN1OctetString.getInstance(o).getOctets()); 070 } 071 } 072 073 /** 074 * basic constructor - with bytes. 075 */ 076 DERNumericString( 077 byte[] string) 078 { 079 this.string = string; 080 } 081 082 /** 083 * basic constructor - without validation.. 084 */ 085 public DERNumericString( 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 NumericString. 098 */ 099 public DERNumericString( 100 String string, 101 boolean validate) 102 { 103 if (validate && !isNumericString(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 String toString() 117 { 118 return getString(); 119 } 120 121 public byte[] getOctets() 122 { 123 return Arrays.clone(string); 124 } 125 126 boolean isConstructed() 127 { 128 return false; 129 } 130 131 int encodedLength() 132 { 133 return 1 + StreamUtil.calculateBodyLength(string.length) + string.length; 134 } 135 136 void encode( 137 ASN1OutputStream out) 138 throws IOException 139 { 140 out.writeEncoded(BERTags.NUMERIC_STRING, string); 141 } 142 143 public int hashCode() 144 { 145 return Arrays.hashCode(string); 146 } 147 148 boolean asn1Equals( 149 ASN1Primitive o) 150 { 151 if (!(o instanceof DERNumericString)) 152 { 153 return false; 154 } 155 156 DERNumericString s = (DERNumericString)o; 157 158 return Arrays.areEqual(string, s.string); 159 } 160 161 /** 162 * Return true if the string can be represented as a NumericString ('0'..'9', ' ') 163 * 164 * @param str string to validate. 165 * @return true if numeric, fale otherwise. 166 */ 167 public static boolean isNumericString( 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 (('0' <= ch && ch <= '9') || ch == ' ') 180 { 181 continue; 182 } 183 184 return false; 185 } 186 187 return true; 188 } 189}