001 /** 002 * 003 * Licensed to the Apache Software Foundation (ASF) under one or more 004 * contributor license agreements. See the NOTICE file distributed with 005 * this work for additional information regarding copyright ownership. 006 * The ASF licenses this file to You under the Apache License, Version 2.0 007 * (the "License"); you may not use this file except in compliance with 008 * the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 019 package org.apache.geronimo.util.asn1; 020 021 import java.io.ByteArrayOutputStream; 022 import java.io.IOException; 023 024 public class DERBitString 025 extends DERObject 026 implements DERString 027 { 028 private static final char[] table = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; 029 030 protected byte[] data; 031 protected int padBits; 032 033 /** 034 * return the correct number of pad bits for a bit string defined in 035 * a 32 bit constant 036 */ 037 static protected int getPadBits( 038 int bitString) 039 { 040 int val = 0; 041 for (int i = 3; i >= 0; i--) 042 { 043 // 044 // this may look a little odd, but if it isn't done like this pre jdk1.2 045 // JVM's break! 046 // 047 if (i != 0) 048 { 049 if ((bitString >> (i * 8)) != 0) 050 { 051 val = (bitString >> (i * 8)) & 0xFF; 052 break; 053 } 054 } 055 else 056 { 057 if (bitString != 0) 058 { 059 val = bitString & 0xFF; 060 break; 061 } 062 } 063 } 064 065 if (val == 0) 066 { 067 return 7; 068 } 069 070 071 int bits = 1; 072 073 while (((val <<= 1) & 0xFF) != 0) 074 { 075 bits++; 076 } 077 078 return 8 - bits; 079 } 080 081 /** 082 * return the correct number of bytes for a bit string defined in 083 * a 32 bit constant 084 */ 085 static protected byte[] getBytes(int bitString) 086 { 087 int bytes = 4; 088 for (int i = 3; i >= 1; i--) 089 { 090 if ((bitString & (0xFF << (i * 8))) != 0) 091 { 092 break; 093 } 094 bytes--; 095 } 096 097 byte[] result = new byte[bytes]; 098 for (int i = 0; i < bytes; i++) 099 { 100 result[i] = (byte) ((bitString >> (i * 8)) & 0xFF); 101 } 102 103 return result; 104 } 105 106 /** 107 * return a Bit String from the passed in object 108 * 109 * @exception IllegalArgumentException if the object cannot be converted. 110 */ 111 public static DERBitString getInstance( 112 Object obj) 113 { 114 if (obj == null || obj instanceof DERBitString) 115 { 116 return (DERBitString)obj; 117 } 118 119 if (obj instanceof ASN1OctetString) 120 { 121 byte[] bytes = ((ASN1OctetString)obj).getOctets(); 122 int padBits = bytes[0]; 123 byte[] data = new byte[bytes.length - 1]; 124 125 System.arraycopy(bytes, 1, data, 0, bytes.length - 1); 126 127 return new DERBitString(data, padBits); 128 } 129 130 if (obj instanceof ASN1TaggedObject) 131 { 132 return getInstance(((ASN1TaggedObject)obj).getObject()); 133 } 134 135 throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); 136 } 137 138 /** 139 * return a Bit String from a tagged object. 140 * 141 * @param obj the tagged object holding the object we want 142 * @param explicit true if the object is meant to be explicitly 143 * tagged false otherwise. 144 * @exception IllegalArgumentException if the tagged object cannot 145 * be converted. 146 */ 147 public static DERBitString getInstance( 148 ASN1TaggedObject obj, 149 boolean explicit) 150 { 151 return getInstance(obj.getObject()); 152 } 153 154 protected DERBitString( 155 byte data, 156 int padBits) 157 { 158 this.data = new byte[1]; 159 this.data[0] = data; 160 this.padBits = padBits; 161 } 162 163 /** 164 * @param data the octets making up the bit string. 165 * @param padBits the number of extra bits at the end of the string. 166 */ 167 public DERBitString( 168 byte[] data, 169 int padBits) 170 { 171 this.data = data; 172 this.padBits = padBits; 173 } 174 175 public DERBitString( 176 byte[] data) 177 { 178 this(data, 0); 179 } 180 181 public DERBitString( 182 DEREncodable obj) 183 { 184 try 185 { 186 ByteArrayOutputStream bOut = new ByteArrayOutputStream(); 187 DEROutputStream dOut = new DEROutputStream(bOut); 188 189 dOut.writeObject(obj); 190 dOut.close(); 191 192 this.data = bOut.toByteArray(); 193 this.padBits = 0; 194 } 195 catch (IOException e) 196 { 197 throw new IllegalArgumentException("Error processing object : " + e.toString()); 198 } 199 } 200 201 public byte[] getBytes() 202 { 203 return data; 204 } 205 206 public int getPadBits() 207 { 208 return padBits; 209 } 210 211 212 /** 213 * @return the value of the bit string as an int (truncating if necessary) 214 */ 215 public int intValue() 216 { 217 int value = 0; 218 219 for (int i = 0; i != data.length && i != 4; i++) 220 { 221 value |= (data[i] & 0xff) << (8 * i); 222 } 223 224 return value; 225 } 226 227 void encode( 228 DEROutputStream out) 229 throws IOException 230 { 231 byte[] bytes = new byte[getBytes().length + 1]; 232 233 bytes[0] = (byte)getPadBits(); 234 System.arraycopy(getBytes(), 0, bytes, 1, bytes.length - 1); 235 236 out.writeEncoded(BIT_STRING, bytes); 237 } 238 239 public int hashCode() 240 { 241 int value = 0; 242 243 for (int i = 0; i != data.length; i++) 244 { 245 value ^= (data[i] & 0xff) << (i % 4); 246 } 247 248 return value; 249 } 250 251 public boolean equals( 252 Object o) 253 { 254 if (o == null || !(o instanceof DERBitString)) 255 { 256 return false; 257 } 258 259 DERBitString other = (DERBitString)o; 260 261 if (data.length != other.data.length) 262 { 263 return false; 264 } 265 266 for (int i = 0; i != data.length; i++) 267 { 268 if (data[i] != other.data[i]) 269 { 270 return false; 271 } 272 } 273 274 return (padBits == other.padBits); 275 } 276 277 public String getString() 278 { 279 StringBuffer buf = new StringBuffer("#"); 280 ByteArrayOutputStream bOut = new ByteArrayOutputStream(); 281 ASN1OutputStream aOut = new ASN1OutputStream(bOut); 282 283 try 284 { 285 aOut.writeObject(this); 286 } 287 catch (IOException e) 288 { 289 throw new RuntimeException("internal error encoding BitString"); 290 } 291 292 byte[] string = bOut.toByteArray(); 293 294 for (int i = 0; i != string.length; i++) 295 { 296 buf.append(table[(string[i] >>> 4) % 0xf]); 297 buf.append(table[string[i] & 0xf]); 298 } 299 300 return buf.toString(); 301 } 302 }