package org.bouncycastle.asn1.x509; import org.bouncycastle.asn1.DERObjectIdentifier; // BEGIN android-note // This class was extracted from X509Name as a way to keep the element // list in a more controlled fashion. Also, unlike the original code, // this class imposes a 32 element limit. We have never observed an // instance created with more than 10, so the limit seems reasonable. // END android-note /** * List of elements of an X509 name. Each element has a key, a value, and * an "added" flag. */ public class X509NameElementList { /** null-ok; key #0 */ private DERObjectIdentifier key0; /** null-ok; key #1 */ private DERObjectIdentifier key1; /** null-ok; key #2 */ private DERObjectIdentifier key2; /** null-ok; key #3 */ private DERObjectIdentifier key3; /** null-ok; value #0 */ private String value0; /** null-ok; value #1 */ private String value1; /** null-ok; value #2 */ private String value2; /** null-ok; value #3 */ private String value3; /** * null-ok; array of additional keys and values, alternating * key then value, etc. */ private Object[] rest; /** bit vector (in int form) for all the "added" bits */ private int added; /** >= 0; number of elements in the list */ private int size; // Note: Default public constructor. /** * Adds an element. The "added" flag is set to false for the element. * * @param key non-null; the key * @param value non-null; the value */ public void add(DERObjectIdentifier key, String value) { add(key, value, false); } /** * Adds an element. * * @param key non-null; the key * @param value non-null; the value * @param added the added bit */ public void add(DERObjectIdentifier key, String value, boolean added) { if (size >= 32) { throw new UnsupportedOperationException( "no more than 32 elements"); } if (key == null) { throw new NullPointerException("key == null"); } if (value == null) { throw new NullPointerException("value == null"); } int sz = size; switch (sz) { case 0: { key0 = key; value0 = value; break; } case 1: { key1 = key; value1 = value; break; } case 2: { key2 = key; value2 = value; break; } case 3: { key3 = key; value3 = value; break; } case 4: { // Do initial allocation of rest. rest = new Object[10]; rest[0] = key; rest[1] = value; break; } case 9: { // Grow to accommodate 28 pairs in the array. Object[] newRest = new Object[56]; System.arraycopy(rest, 0, newRest, 0, 10); rest = newRest; // Fall through. } default: { int index = (sz - 4) * 2; rest[index] = key; rest[index + 1] = value; break; } } if (added) { this.added |= (1 << sz); } size = sz + 1; } /** * Sets the "added" flag on the most recently added element. */ public void setLastAddedFlag() { added |= 1 << (size - 1); } /** * Gets the number of elements in this instance. */ public int size() { return size; } /** * Gets the nth key. * * @param n index * @return non-null; the nth key */ public DERObjectIdentifier getKey(int n) { if ((n < 0) || (n >= size)) { throw new IndexOutOfBoundsException(Integer.toString(n)); } switch (n) { case 0: return key0; case 1: return key1; case 2: return key2; case 3: return key3; default: return (DERObjectIdentifier) rest[(n - 4) * 2]; } } /** * Gets the nth value. * * @param n index * @return non-null; the nth value */ public String getValue(int n) { if ((n < 0) || (n >= size)) { throw new IndexOutOfBoundsException(Integer.toString(n)); } switch (n) { case 0: return value0; case 1: return value1; case 2: return value2; case 3: return value3; default: return (String) rest[((n - 4) * 2) + 1]; } } /** * Gets the nth added flag bit. * * @param n index * @return the nth added flag bit */ public boolean getAdded(int n) { if ((n < 0) || (n >= size)) { throw new IndexOutOfBoundsException(Integer.toString(n)); } return (added & (1 << n)) != 0; } /** * Constructs and returns a new instance which consists of the * elements of this one in reverse order * * @return non-null; the reversed instance */ public X509NameElementList reverse() { X509NameElementList result = new X509NameElementList(); for (int i = size - 1; i >= 0; i--) { result.add(getKey(i), getValue(i), getAdded(i)); } return result; } }