Merge from mainline (gomp-merge-2005-02-26).
[official-gcc.git] / libjava / gnu / java / security / OID.java
blob0b935c48c2388c4afb551ee97e6245d6591cf685
1 /* OID.java -- numeric representation of an object identifier
2 Copyright (C) 2003, 2004 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA.
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package gnu.java.security;
41 import gnu.java.security.der.DEREncodingException;
43 import java.io.ByteArrayOutputStream;
44 import java.io.InputStream;
45 import java.io.IOException;
46 import java.util.StringTokenizer;
48 /**
49 * This immutable class represents an object identifier, or OID.
51 * <p>OIDs are represented as a series of hierarcical tokens, each of
52 * which is usually represented as a single, unsigned integer. The
53 * hierarchy works so that later tokens are considered within the group
54 * of earlier tokens. Thus, the OID for the Serpent block cipher,
55 * 1.3.6.1.4.1.11591.13.2, is maintained by the GNU project, whose OID
56 * is 1.3.6.1.4.1.11591 (which is, in turn, part of bigger, more general
57 * bodies; the topmost, 1, stands for the OIDs assigned by the
58 * International Standards Organization, ISO).
60 * <p>OIDs can be represented in a variety of ways, including the
61 * dotted-decimal form we use here.
63 * <p>OIDs may be relative, in which case the first two elements of the
64 * OID are omitted.
66 * @author Casey Marshall (csm@gnu.org)
68 public class OID implements Cloneable, Comparable, java.io.Serializable
71 // Fields.
72 // ------------------------------------------------------------------------
74 /**
75 * The numeric ID structure.
77 private int[] components;
79 /**
80 * The string representation of this OID, in dotted-decimal format.
82 private transient String strRep;
84 /**
85 * The DER encoding of this OID.
87 private transient byte[] der;
89 /**
90 * Whether or not this OID is relative.
92 private boolean relative;
94 // Constructors.
95 // ------------------------------------------------------------------------
97 /**
98 * Create a new OID from the given byte array. The argument (which can
99 * neither be null nor zero-length) is copied to prevent subsequent
100 * modification.
102 * @param components The numeric IDs.
103 * @throws IllegalArgumentException If <i>components</i> is null or empty.
105 public OID(int[] components)
107 this(components, false);
111 * Create a new OID from the given byte array. The argument (which can
112 * neither be null nor zero-length) is copied to prevent subsequent
113 * modification.
115 * @param components The numeric IDs.
116 * @param relative The relative flag.
117 * @throws IllegalArgumentException If <i>components</i> is null or empty.
119 public OID(int[] components, boolean relative)
121 if (components == null || components.length == 0)
122 throw new IllegalArgumentException();
123 this.components = (int[]) components.clone();
124 this.relative = relative;
128 * Create a new OID from the given dotted-decimal representation.
130 * @param strRep The string representation of the OID.
131 * @throws IllegalArgumentException If the string does not contain at
132 * least one integer.
133 * @throws NumberFormatException If the string does not contain only
134 * numbers and periods ('.').
136 public OID(String strRep)
138 this(strRep, false);
142 * Create a new OID from the given dotted-decimal representation.
144 * @param strRep The string representation of the OID.
145 * @param relative The relative flag.
146 * @throws IllegalArgumentException If the string does not contain at
147 * least one integer.
148 * @throws NumberFormatException If the string does not contain only
149 * numbers and periods ('.').
151 public OID(String strRep, boolean relative)
153 this.relative = relative;
154 this.strRep = strRep;
155 components = fromString(strRep);
159 * Construct a new OID from the DER bytes in an input stream. This method
160 * does not read the tag or the length field from the input stream, so
161 * the caller must supply the number of octets in this OID's encoded
162 * form.
164 * @param derIn The DER input stream.
165 * @param len The number of bytes in the encoded form.
166 * @throws IOException If an error occurs reading the OID.
168 public OID(InputStream derIn, int len) throws IOException
170 this(derIn, len, false);
174 * Construct a new OID from the DER bytes in an input stream. This method
175 * does not read the tag or the length field from the input stream, so
176 * the caller must supply the number of octets in this OID's encoded
177 * form.
179 * @param derIn The DER input stream.
180 * @param len The number of bytes in the encoded form.
181 * @param relative The relative flag.
182 * @throws IOException If an error occurs reading the OID.
184 public OID(InputStream derIn, int len, boolean relative) throws IOException
186 der = new byte[len];
187 derIn.read(der);
188 this.relative = relative;
191 components = fromDER(der, relative);
193 catch (ArrayIndexOutOfBoundsException aioobe)
195 aioobe.printStackTrace();
196 throw aioobe;
201 * Construct a new OID from the given DER bytes.
203 * @param encoded The DER encoded OID.
204 * @throws IOException If an error occurs reading the OID.
206 public OID(byte[] encoded) throws IOException
208 this(encoded, false);
212 * Construct a new OID from the given DER bytes.
214 * @param root The root OID.
215 * @param encoded The encoded relative OID.
216 * @param relative The relative flag.
218 public OID(byte[] encoded, boolean relative) throws IOException
220 der = (byte[]) encoded.clone();
221 this.relative = relative;
224 components = fromDER(der, relative);
226 catch (ArrayIndexOutOfBoundsException aioobe)
228 aioobe.printStackTrace();
229 throw aioobe;
234 * Our private constructor.
236 private OID()
240 // Instance methods.
241 // ------------------------------------------------------------------------
244 * Return the numeric IDs of this OID. The value returned is copied to
245 * prevent modification.
247 * @return The IDs in a new integer array.
249 public int[] getIDs()
251 return (int[]) components.clone();
255 * Get the DER encoding of this OID, minus the tag and length fields.
257 * @return The DER bytes.
259 public byte[] getDER()
261 if (der == null)
263 ByteArrayOutputStream bout = new ByteArrayOutputStream();
264 int i = 0;
265 if (!relative)
267 int b = components[i++] * 40 + (components.length > 1
268 ? components[i++] : 0);
269 encodeSubID(bout, b);
271 for ( ; i < components.length; i++)
272 encodeSubID(bout, components[i]);
273 der = bout.toByteArray();
275 return (byte[]) der.clone();
279 * Get the parent OID of this OID. That is, if this OID is "1.2.3.4",
280 * then the parent OID will be "1.2.3". If this OID is a top-level
281 * OID, this method returns null.
283 * @return The parent OID, or null.
285 public OID getParent()
287 if (components.length == 1)
288 return null;
289 int[] parent = new int[components.length - 1];
290 System.arraycopy(components, 0, parent, 0, parent.length);
291 return new OID(parent);
294 public OID getChild(int id)
296 int[] child = new int[components.length + 1];
297 System.arraycopy(components, 0, child, 0, components.length);
298 child[child.length - 1] = id;
299 return new OID(child);
303 * Get the root OID of this OID. That is, the first two components.
305 * @return The root OID.
307 public OID getRoot()
309 if (components.length <= 2)
310 return this;
311 int[] root = new int[2];
312 root[0] = components[0];
313 root[1] = components[1];
314 return new OID(root);
317 public boolean isRelative()
319 return relative;
323 * Returns a copy of this OID.
325 * @return The copy.
327 public Object clone()
329 OID oid = new OID();
330 oid.components = this.components;
331 oid.strRep = this.strRep;
332 return oid;
335 /* Nice idea, but possibly too expensive for whatever benefit it
336 * provides.
338 public String getShortName()
340 return OIDTable.getShortName(this);
343 public String getLongName()
345 return OIDTable.getLongName(this);
351 * Returns the value of this OID in dotted-decimal format.
353 * @return The string representation.
355 public String toString()
357 if (strRep != null)
358 return strRep;
359 else
361 StringBuffer buf = new StringBuffer();
362 for (int i = 0; i < components.length; i++)
364 buf.append((long) components[i] & 0xFFFFFFFFL);
365 if (i < components.length - 1)
366 buf.append('.');
368 return (strRep = buf.toString());
373 * Computes a hash code for this OID.
375 * @return The hash code.
377 public int hashCode()
379 int ret = 0;
380 for (int i = 0; i < components.length; i++)
381 ret += components[i] << (i & 31);
382 return ret;
386 * Tests whether or not this OID equals another.
388 * @return Whether or not this OID equals the other.
390 public boolean equals(Object o)
392 if (!(o instanceof OID))
393 return false;
394 return java.util.Arrays.equals(components, ((OID) o).components);
398 * Compares this OID to another. The comparison is essentially
399 * lexicographic, where the two OIDs are compared until their
400 * first difference, then that difference is returned. If one OID is
401 * shorter, but all elements equal between the two for the shorter
402 * length, then the shorter OID is lesser than the longer.
404 * @param o The object to compare.
405 * @return An integer less than, equal to, or greater than zero if
406 * this object is less than, equal to, or greater than the
407 * argument.
408 * @throws ClassCastException If <i>o</i> is not an OID.
410 public int compareTo(Object o)
412 if (equals(o))
413 return 0;
414 int[] components2 = ((OID) o).components;
415 int len = Math.min(components.length, components2.length);
416 for (int i = 0; i < len; i++)
418 if (components[i] != components2[i])
419 return (components[i] < components2[i]) ? -1 : 1;
421 if (components.length == components2.length)
422 return 0;
423 return (components.length < components2.length) ? -1 : 1;
426 // Own methods.
427 // ------------------------------------------------------------------------
429 private static int[] fromDER(byte[] der, boolean relative)
430 throws DEREncodingException
432 // cannot be longer than this.
433 int[] components = new int[der.length + 1];
434 int count = 0;
435 int i = 0;
436 if (!relative && i < der.length)
438 // Non-relative OIDs have the first two arcs coded as:
440 // i = first_arc * 40 + second_arc;
442 int j = (der[i] & 0xFF);
443 components[count++] = j / 40;
444 components[count++] = j % 40;
445 i++;
447 while (i < der.length)
449 int j = 0;
452 j = der[i++] & 0xFF;
453 components[count] <<= 7;
454 components[count] |= j & 0x7F;
455 if (i >= der.length && (j & 0x80) != 0)
456 throw new DEREncodingException("malformed OID");
458 while ((j & 0x80) != 0);
459 count++;
461 if (count == components.length)
462 return components;
463 int[] ret = new int[count];
464 System.arraycopy(components, 0, ret, 0, count);
465 return ret;
468 private static int[] fromString(String strRep) throws NumberFormatException
470 if (strRep.startsWith("OID.") || strRep.startsWith("oid."))
471 strRep = strRep.substring(4);
472 StringTokenizer tok = new StringTokenizer(strRep, ".");
473 if (tok.countTokens() == 0)
474 throw new IllegalArgumentException();
475 int[] components = new int[tok.countTokens()];
476 int i = 0;
477 while (tok.hasMoreTokens())
479 components[i++] = Integer.parseInt(tok.nextToken());
481 return components;
484 private static void encodeSubID(ByteArrayOutputStream out, int id)
486 if (id < 128)
488 out.write(id);
490 else if (id < 16384)
492 out.write((id >>> 7) | 0x80);
493 out.write(id & 0x7F);
495 else if (id < 2097152)
497 out.write((id >>> 14) | 0x80);
498 out.write(((id >>> 7) | 0x80) & 0xFF);
499 out.write(id & 0x7F);
501 else if (id < 268435456)
503 out.write( (id >>> 21) | 0x80);
504 out.write(((id >>> 14) | 0x80) & 0xFF);
505 out.write(((id >>> 7) | 0x80) & 0xFF);
506 out.write(id & 0x7F);