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 import java.util.Enumeration; 024 import java.util.Vector; 025 026 abstract public class ASN1Set 027 extends DERObject 028 { 029 protected Vector set = new Vector(); 030 031 /** 032 * return an ASN1Set from the given object. 033 * 034 * @param obj the object we want converted. 035 * @exception IllegalArgumentException if the object cannot be converted. 036 */ 037 public static ASN1Set getInstance( 038 Object obj) 039 { 040 if (obj == null || obj instanceof ASN1Set) 041 { 042 return (ASN1Set)obj; 043 } 044 045 throw new IllegalArgumentException("unknown object in getInstance"); 046 } 047 048 /** 049 * Return an ASN1 set from a tagged object. There is a special 050 * case here, if an object appears to have been explicitly tagged on 051 * reading but we were expecting it to be implictly tagged in the 052 * normal course of events it indicates that we lost the surrounding 053 * set - so we need to add it back (this will happen if the tagged 054 * object is a sequence that contains other sequences). If you are 055 * dealing with implicitly tagged sets you really <b>should</b> 056 * be using this method. 057 * 058 * @param obj the tagged object. 059 * @param explicit true if the object is meant to be explicitly tagged 060 * false otherwise. 061 * @exception IllegalArgumentException if the tagged object cannot 062 * be converted. 063 */ 064 public static ASN1Set getInstance( 065 ASN1TaggedObject obj, 066 boolean explicit) 067 { 068 if (explicit) 069 { 070 if (!obj.isExplicit()) 071 { 072 throw new IllegalArgumentException("object implicit - explicit expected."); 073 } 074 075 return (ASN1Set)obj.getObject(); 076 } 077 else 078 { 079 // 080 // constructed object which appears to be explicitly tagged 081 // and it's really implicit means we have to add the 082 // surrounding sequence. 083 // 084 if (obj.isExplicit()) 085 { 086 ASN1Set set = new DERSet(obj.getObject()); 087 088 return set; 089 } 090 else 091 { 092 if (obj.getObject() instanceof ASN1Set) 093 { 094 return (ASN1Set)obj.getObject(); 095 } 096 097 // 098 // in this case the parser returns a sequence, convert it 099 // into a set. 100 // 101 ASN1EncodableVector v = new ASN1EncodableVector(); 102 103 if (obj.getObject() instanceof ASN1Sequence) 104 { 105 ASN1Sequence s = (ASN1Sequence)obj.getObject(); 106 Enumeration e = s.getObjects(); 107 108 while (e.hasMoreElements()) 109 { 110 v.add((DEREncodable)e.nextElement()); 111 } 112 113 return new DERSet(v, false); 114 } 115 } 116 } 117 118 throw new IllegalArgumentException( 119 "unknown object in getInstanceFromTagged"); 120 } 121 122 public ASN1Set() 123 { 124 } 125 126 public Enumeration getObjects() 127 { 128 return set.elements(); 129 } 130 131 /** 132 * return the object at the set postion indicated by index. 133 * 134 * @param index the set number (starting at zero) of the object 135 * @return the object at the set postion indicated by index. 136 */ 137 public DEREncodable getObjectAt( 138 int index) 139 { 140 return (DEREncodable)set.elementAt(index); 141 } 142 143 /** 144 * return the number of objects in this set. 145 * 146 * @return the number of objects in this set. 147 */ 148 public int size() 149 { 150 return set.size(); 151 } 152 153 public int hashCode() 154 { 155 Enumeration e = this.getObjects(); 156 int hashCode = 0; 157 158 while (e.hasMoreElements()) 159 { 160 hashCode ^= e.nextElement().hashCode(); 161 } 162 163 return hashCode; 164 } 165 166 public boolean equals( 167 Object o) 168 { 169 if (o == null || !(o instanceof ASN1Set)) 170 { 171 return false; 172 } 173 174 ASN1Set other = (ASN1Set)o; 175 176 if (this.size() != other.size()) 177 { 178 return false; 179 } 180 181 Enumeration s1 = this.getObjects(); 182 Enumeration s2 = other.getObjects(); 183 184 while (s1.hasMoreElements()) 185 { 186 if (!s1.nextElement().equals(s2.nextElement())) 187 { 188 return false; 189 } 190 } 191 192 return true; 193 } 194 195 /** 196 * return true if a <= b (arrays are assumed padded with zeros). 197 */ 198 private boolean lessThanOrEqual( 199 byte[] a, 200 byte[] b) 201 { 202 if (a.length <= b.length) 203 { 204 for (int i = 0; i != a.length; i++) 205 { 206 int l = a[i] & 0xff; 207 int r = b[i] & 0xff; 208 209 if (r > l) 210 { 211 return true; 212 } 213 else if (l > r) 214 { 215 return false; 216 } 217 } 218 219 return true; 220 } 221 else 222 { 223 for (int i = 0; i != b.length; i++) 224 { 225 int l = a[i] & 0xff; 226 int r = b[i] & 0xff; 227 228 if (r > l) 229 { 230 return true; 231 } 232 else if (l > r) 233 { 234 return false; 235 } 236 } 237 238 return false; 239 } 240 } 241 242 private byte[] getEncoded( 243 DEREncodable obj) 244 { 245 ByteArrayOutputStream bOut = new ByteArrayOutputStream(); 246 ASN1OutputStream aOut = new ASN1OutputStream(bOut); 247 248 try 249 { 250 aOut.writeObject(obj); 251 } 252 catch (IOException e) 253 { 254 throw new IllegalArgumentException("cannot encode object added to SET"); 255 } 256 257 return bOut.toByteArray(); 258 } 259 260 protected void sort() 261 { 262 if (set.size() > 1) 263 { 264 boolean swapped = true; 265 266 while (swapped) 267 { 268 int index = 0; 269 byte[] a = getEncoded((DEREncodable)set.elementAt(0)); 270 271 swapped = false; 272 273 while (index != set.size() - 1) 274 { 275 byte[] b = getEncoded((DEREncodable)set.elementAt(index + 1)); 276 277 if (lessThanOrEqual(a, b)) 278 { 279 a = b; 280 } 281 else 282 { 283 Object o = set.elementAt(index); 284 285 set.setElementAt(set.elementAt(index + 1), index); 286 set.setElementAt(o, index + 1); 287 288 swapped = true; 289 } 290 291 index++; 292 } 293 } 294 } 295 } 296 297 protected void addObject( 298 DEREncodable obj) 299 { 300 set.addElement(obj); 301 } 302 303 abstract void encode(DEROutputStream out) 304 throws IOException; 305 }