OSDN Git Service

Merged gcj-eclipse branch to trunk.
[pf3gnuchains/gcc-fork.git] / libjava / classpath / gnu / javax / net / ssl / provider / ExtensionList.java
1 package gnu.javax.net.ssl.provider;
2
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;
9 import java.util.List;
10 import java.util.ListIterator;
11 import java.util.NoSuchElementException;
12
13 /**
14  * A list of extensions, that may appear in either the {@link ClientHello} or
15  * {@link ServerHello}. The form of the extensions list is:
16  * 
17  * <tt>   Extension extensions_list&lt;1..2^16-1&gt;</tt>
18  * 
19  * @author csm
20  */
21 public class ExtensionList implements Builder, Iterable<Extension>
22 {
23   private final ByteBuffer buffer;
24   private int modCount;
25
26   public ExtensionList (ByteBuffer buffer)
27   {
28     this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
29     modCount = 0;
30   }
31   
32   public ExtensionList(List<Extension> extensions)
33   {
34     int length = 2;
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());
41     buffer.rewind();
42   }
43   
44   public ByteBuffer buffer()
45   {
46     return (ByteBuffer) buffer.duplicate().limit(length());
47   }
48
49   public Extension get (final int index)
50   {
51     int length = length ();
52     int i;
53     int n = 0;
54     for (i = 2; i < length && n < index; )
55       {
56         int l = buffer.getShort (i+2) & 0xFFFF;
57         i += l + 4;
58         n++;
59       }
60     if (n < index)
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());
65   }
66   
67   /**
68    * Returns the number of extensions this list contains.
69    * 
70    * @return The number of extensions.
71    */
72   public int size ()
73   {
74     int length = length ();
75     if (length == 0)
76       return 0;
77     int n = 0;
78     for (int i = 2; i < length; )
79       {
80         int len = buffer.getShort (i+2) & 0xFFFF;
81         i += len + 4;
82         n++;
83       }
84     return n;
85   }
86
87   /**
88    * Returns the length of this extension list, in bytes.
89    * 
90    * @return The length of this extension list, in bytes.
91    */
92   public int length ()
93   {
94     return (buffer.getShort (0) & 0xFFFF) + 2;
95   }
96   
97   /**
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.
104    * 
105    * <p>Thus, elements of this list <b>must</b> be set in order of increasing
106    * index.
107    * 
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
111    *  the buffer.
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
115    *  #length()}).
116    */
117   public void set (final int index, Extension e)
118   {
119     int length = length();
120     int n = 0;
121     int i;
122     for (i = 2; i < length && n < index; )
123       {
124         int len = buffer.getShort(i+2) & 0xFFFF;
125         i += len + 4;
126         n++;
127       }
128     if (n < index)
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 "
133                                          + "list length");
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());
137     modCount++;
138   }
139   
140   /**
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.
144    * 
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.
149    */
150   public void set (final int index, Extension.Type t, final int eLength)
151   {
152     int length = length ();
153     int n = 0;
154     int i;
155     for (i = 2; i < length && n < index; )
156       {
157         int len = buffer.getShort (i+2) & 0xFFFF;
158         i += len + 4;
159         n++;
160       }
161     if (n < index)
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 "
166                                           + "list length");
167     buffer.putShort(i, (short) t.getValue());
168     buffer.putShort(i+2, (short) eLength);
169     modCount++;
170   }
171   
172   /**
173    * Set the total length of this list, in bytes.
174    * 
175    * @param newLength The new list length.
176    */
177   public void setLength (final int newLength)
178   {
179     if (newLength < 0 || newLength > 65535)
180       throw new IllegalArgumentException ("invalid length");
181     buffer.putShort (0, (short) newLength);
182     modCount++;
183   }
184   
185   public Iterator<Extension> iterator()
186   {
187     return new ExtensionsIterator();
188   }
189
190   public String toString()
191   {
192     return toString (null);
193   }
194   
195   public String toString(final String prefix)
196   {
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 = ");
203     out.print(length());
204     out.println(";");
205     String subprefix = "  ";
206     if (prefix != null)
207       subprefix = prefix + subprefix;
208     for (Extension e : this)
209       out.println(e.toString(subprefix));
210     if (prefix != null) out.print(prefix);
211     out.print("};");
212     return str.toString();
213   }
214
215   /**
216    * List iterator interface to an extensions list.
217    * 
218    * @author csm@gnu.org
219    */
220   public final class ExtensionsIterator implements ListIterator<Extension>
221   {
222     private final int modCount;
223     private int index;
224     private final int size;
225     
226     public ExtensionsIterator ()
227     {
228       this.modCount = ExtensionList.this.modCount;
229       index = 0;
230       size = size ();
231     }
232
233     public boolean hasNext()
234     {
235       return index < size;
236     }
237
238     public boolean hasPrevious()
239     {
240       return index > 0;
241     }
242
243     public Extension next() throws NoSuchElementException
244     {
245       if (modCount != ExtensionList.this.modCount)
246         throw new ConcurrentModificationException ();
247       if (!hasNext ())
248         throw new NoSuchElementException ();
249       return get (index++);
250     }
251
252     public Extension previous() throws NoSuchElementException
253     {
254       if (modCount != ExtensionList.this.modCount)
255         throw new ConcurrentModificationException ();
256       if (!hasPrevious ())
257         throw new NoSuchElementException ();
258       return get (--index);
259     }
260
261     public int nextIndex()
262     {
263       if (hasNext ())
264         return index + 1;
265       return index;
266     }
267
268     public int previousIndex()
269     {
270       if (hasPrevious ())
271         return index - 1;
272       return -1;
273     }
274
275     public void add(Extension e)
276     {
277       throw new UnsupportedOperationException ("cannot add items to this iterator");
278     }
279
280     public void remove()
281     {
282       throw new UnsupportedOperationException ("cannot remove items from this iterator");
283     }
284
285     public void set(Extension e)
286     {
287       ExtensionList.this.set (index, e);
288     }
289   }
290 }