1 package gnu.javax.net.ssl.provider;
3 import java.io.PrintWriter;
4 import java.io.StringWriter;
5 import java.nio.ByteBuffer;
6 import java.nio.ByteOrder;
7 import java.util.ConcurrentModificationException;
8 import java.util.Iterator;
10 import java.util.ListIterator;
11 import java.util.NoSuchElementException;
14 * A list of extensions, that may appear in either the {@link ClientHello} or
15 * {@link ServerHello}. The form of the extensions list is:
17 * <tt> Extension extensions_list<1..2^16-1></tt>
21 public class ExtensionList implements Builder, Iterable<Extension>
23 private final ByteBuffer buffer;
26 public ExtensionList (ByteBuffer buffer)
28 this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
32 public ExtensionList(List<Extension> extensions)
35 for (Extension extension : extensions)
36 length += extension.length();
37 buffer = ByteBuffer.allocate(length);
38 buffer.putShort((short) (length - 2));
39 for (Extension extension : extensions)
40 buffer.put(extension.buffer());
44 public ByteBuffer buffer()
46 return (ByteBuffer) buffer.duplicate().limit(length());
49 public Extension get (final int index)
51 int length = length ();
54 for (i = 2; i < length && n < index; )
56 int l = buffer.getShort (i+2) & 0xFFFF;
61 throw new IndexOutOfBoundsException ("no elemenet at " + index);
62 int el = buffer.getShort (i+2) & 0xFFFF;
63 ByteBuffer b = (ByteBuffer) buffer.duplicate().position(i).limit(i+el+4);
64 return new Extension(b.slice());
68 * Returns the number of extensions this list contains.
70 * @return The number of extensions.
74 int length = length ();
78 for (int i = 2; i < length; )
80 int len = buffer.getShort (i+2) & 0xFFFF;
88 * Returns the length of this extension list, in bytes.
90 * @return The length of this extension list, in bytes.
94 return (buffer.getShort (0) & 0xFFFF) + 2;
98 * Sets the extension at index <i>i</i> to <i>e</i>. Note that setting an
99 * element at an index <b>may</b> invalidate any other elements that come
100 * after element at index <i>i</i>. In other words, no attempt is made to
101 * move existing elements in this list, and since extensions are variable
102 * length, you can <em>not</em> guarantee that extensions later in the list
103 * will still be valid.
105 * <p>Thus, elements of this list <b>must</b> be set in order of increasing
108 * @param index The index to set the extension at.
109 * @param e The extension.
110 * @throws java.nio.BufferOverflowException If setting the extension overflows
112 * @throws IllegalArgumentException If it isn't possible to find the given index
113 * in the current list (say, if no element index - 1 is set), or if setting
114 * the extension will overflow the current list length (given by {@link
117 public void set (final int index, Extension e)
119 int length = length();
122 for (i = 2; i < length && n < index; )
124 int len = buffer.getShort(i+2) & 0xFFFF;
129 throw new IllegalArgumentException("nothing set at index " + (index-1)
130 + " or insufficient space");
131 if (i + e.length() + 2 > length)
132 throw new IllegalArgumentException("adding this element will exceed the "
134 buffer.putShort(i, (short) e.type().getValue());
135 buffer.putShort(i+2, (short) e.length());
136 ((ByteBuffer) buffer.duplicate().position(i+4)).put (e.valueBuffer());
141 * Reserve space for an extension at index <i>i</i> in the list. In other
142 * words, this does the job of {@link #set(int, Extension)}, but does not
143 * copy the extension value to the underlying buffer.
145 * @param index The index of the extension to reserve space for.
146 * @param t The type of the extension.
147 * @param eLength The number of bytes to reserve for this extension. The total
148 * number of bytes used by this method is this length, plus four.
150 public void set (final int index, Extension.Type t, final int eLength)
152 int length = length ();
155 for (i = 2; i < length && n < index; )
157 int len = buffer.getShort (i+2) & 0xFFFF;
162 throw new IllegalArgumentException ("nothing set at index " + (index-1)
163 + " or insufficient space");
164 if (i + eLength + 2 > length)
165 throw new IllegalArgumentException ("adding this element will exceed the "
167 buffer.putShort(i, (short) t.getValue());
168 buffer.putShort(i+2, (short) eLength);
173 * Set the total length of this list, in bytes.
175 * @param newLength The new list length.
177 public void setLength (final int newLength)
179 if (newLength < 0 || newLength > 65535)
180 throw new IllegalArgumentException ("invalid length");
181 buffer.putShort (0, (short) newLength);
185 public Iterator<Extension> iterator()
187 return new ExtensionsIterator();
190 public String toString()
192 return toString (null);
195 public String toString(final String prefix)
197 StringWriter str = new StringWriter();
198 PrintWriter out = new PrintWriter(str);
199 if (prefix != null) out.print(prefix);
200 out.println("ExtensionList {");
201 if (prefix != null) out.print(prefix);
202 out.print(" length = ");
205 String subprefix = " ";
207 subprefix = prefix + subprefix;
208 for (Extension e : this)
209 out.println(e.toString(subprefix));
210 if (prefix != null) out.print(prefix);
212 return str.toString();
216 * List iterator interface to an extensions list.
218 * @author csm@gnu.org
220 public final class ExtensionsIterator implements ListIterator<Extension>
222 private final int modCount;
224 private final int size;
226 public ExtensionsIterator ()
228 this.modCount = ExtensionList.this.modCount;
233 public boolean hasNext()
238 public boolean hasPrevious()
243 public Extension next() throws NoSuchElementException
245 if (modCount != ExtensionList.this.modCount)
246 throw new ConcurrentModificationException ();
248 throw new NoSuchElementException ();
249 return get (index++);
252 public Extension previous() throws NoSuchElementException
254 if (modCount != ExtensionList.this.modCount)
255 throw new ConcurrentModificationException ();
257 throw new NoSuchElementException ();
258 return get (--index);
261 public int nextIndex()
268 public int previousIndex()
275 public void add(Extension e)
277 throw new UnsupportedOperationException ("cannot add items to this iterator");
282 throw new UnsupportedOperationException ("cannot remove items from this iterator");
285 public void set(Extension e)
287 ExtensionList.this.set (index, e);