001: /**
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */package org.apache.geronimo.crypto.asn1;
017:
018: import java.io.ByteArrayOutputStream;
019: import java.io.IOException;
020: import java.util.Enumeration;
021: import java.util.Vector;
022:
023: abstract public class ASN1Set extends DERObject {
024: protected Vector set = new Vector();
025:
026: /**
027: * return an ASN1Set from the given object.
028: *
029: * @param obj the object we want converted.
030: * @exception IllegalArgumentException if the object cannot be converted.
031: */
032: public static ASN1Set getInstance(Object obj) {
033: if (obj == null || obj instanceof ASN1Set) {
034: return (ASN1Set) obj;
035: }
036:
037: throw new IllegalArgumentException(
038: "unknown object in getInstance");
039: }
040:
041: /**
042: * Return an ASN1 set from a tagged object. There is a special
043: * case here, if an object appears to have been explicitly tagged on
044: * reading but we were expecting it to be implictly tagged in the
045: * normal course of events it indicates that we lost the surrounding
046: * set - so we need to add it back (this will happen if the tagged
047: * object is a sequence that contains other sequences). If you are
048: * dealing with implicitly tagged sets you really <b>should</b>
049: * be using this method.
050: *
051: * @param obj the tagged object.
052: * @param explicit true if the object is meant to be explicitly tagged
053: * false otherwise.
054: * @exception IllegalArgumentException if the tagged object cannot
055: * be converted.
056: */
057: public static ASN1Set getInstance(ASN1TaggedObject obj,
058: boolean explicit) {
059: if (explicit) {
060: if (!obj.isExplicit()) {
061: throw new IllegalArgumentException(
062: "object implicit - explicit expected.");
063: }
064:
065: return (ASN1Set) obj.getObject();
066: } else {
067: //
068: // constructed object which appears to be explicitly tagged
069: // and it's really implicit means we have to add the
070: // surrounding sequence.
071: //
072: if (obj.isExplicit()) {
073: ASN1Set set = new DERSet(obj.getObject());
074:
075: return set;
076: } else {
077: if (obj.getObject() instanceof ASN1Set) {
078: return (ASN1Set) obj.getObject();
079: }
080:
081: //
082: // in this case the parser returns a sequence, convert it
083: // into a set.
084: //
085: ASN1EncodableVector v = new ASN1EncodableVector();
086:
087: if (obj.getObject() instanceof ASN1Sequence) {
088: ASN1Sequence s = (ASN1Sequence) obj.getObject();
089: Enumeration e = s.getObjects();
090:
091: while (e.hasMoreElements()) {
092: v.add((DEREncodable) e.nextElement());
093: }
094:
095: return new DERSet(v, false);
096: }
097: }
098: }
099:
100: throw new IllegalArgumentException(
101: "unknown object in getInstanceFromTagged");
102: }
103:
104: public ASN1Set() {
105: }
106:
107: public Enumeration getObjects() {
108: return set.elements();
109: }
110:
111: /**
112: * return the object at the set postion indicated by index.
113: *
114: * @param index the set number (starting at zero) of the object
115: * @return the object at the set postion indicated by index.
116: */
117: public DEREncodable getObjectAt(int index) {
118: return (DEREncodable) set.elementAt(index);
119: }
120:
121: /**
122: * return the number of objects in this set.
123: *
124: * @return the number of objects in this set.
125: */
126: public int size() {
127: return set.size();
128: }
129:
130: public int hashCode() {
131: Enumeration e = this .getObjects();
132: int hashCode = 0;
133:
134: while (e.hasMoreElements()) {
135: hashCode ^= e.nextElement().hashCode();
136: }
137:
138: return hashCode;
139: }
140:
141: public boolean equals(Object o) {
142: if (o == null || !(o instanceof ASN1Set)) {
143: return false;
144: }
145:
146: ASN1Set other = (ASN1Set) o;
147:
148: if (this .size() != other.size()) {
149: return false;
150: }
151:
152: Enumeration s1 = this .getObjects();
153: Enumeration s2 = other.getObjects();
154:
155: while (s1.hasMoreElements()) {
156: if (!s1.nextElement().equals(s2.nextElement())) {
157: return false;
158: }
159: }
160:
161: return true;
162: }
163:
164: /**
165: * return true if a <= b (arrays are assumed padded with zeros).
166: */
167: private boolean lessThanOrEqual(byte[] a, byte[] b) {
168: if (a.length <= b.length) {
169: for (int i = 0; i != a.length; i++) {
170: int l = a[i] & 0xff;
171: int r = b[i] & 0xff;
172:
173: if (r > l) {
174: return true;
175: } else if (l > r) {
176: return false;
177: }
178: }
179:
180: return true;
181: } else {
182: for (int i = 0; i != b.length; i++) {
183: int l = a[i] & 0xff;
184: int r = b[i] & 0xff;
185:
186: if (r > l) {
187: return true;
188: } else if (l > r) {
189: return false;
190: }
191: }
192:
193: return false;
194: }
195: }
196:
197: private byte[] getEncoded(DEREncodable obj) {
198: ByteArrayOutputStream bOut = new ByteArrayOutputStream();
199: ASN1OutputStream aOut = new ASN1OutputStream(bOut);
200:
201: try {
202: aOut.writeObject(obj);
203: } catch (IOException e) {
204: throw new IllegalArgumentException(
205: "cannot encode object added to SET", e);
206: }
207:
208: return bOut.toByteArray();
209: }
210:
211: protected void sort() {
212: if (set.size() > 1) {
213: boolean swapped = true;
214:
215: while (swapped) {
216: int index = 0;
217: byte[] a = getEncoded((DEREncodable) set.elementAt(0));
218:
219: swapped = false;
220:
221: while (index != set.size() - 1) {
222: byte[] b = getEncoded((DEREncodable) set
223: .elementAt(index + 1));
224:
225: if (lessThanOrEqual(a, b)) {
226: a = b;
227: } else {
228: Object o = set.elementAt(index);
229:
230: set.setElementAt(set.elementAt(index + 1),
231: index);
232: set.setElementAt(o, index + 1);
233:
234: swapped = true;
235: }
236:
237: index++;
238: }
239: }
240: }
241: }
242:
243: protected void addObject(DEREncodable obj) {
244: set.addElement(obj);
245: }
246:
247: abstract void encode(DEROutputStream out) throws IOException;
248: }
|