001 /*
002 * Copyright 2007-2013 UnboundID Corp.
003 * All Rights Reserved.
004 */
005 /*
006 * Copyright (C) 2008-2013 UnboundID Corp.
007 *
008 * This program is free software; you can redistribute it and/or modify
009 * it under the terms of the GNU General Public License (GPLv2 only)
010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
011 * as published by the Free Software Foundation.
012 *
013 * This program is distributed in the hope that it will be useful,
014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016 * GNU General Public License for more details.
017 *
018 * You should have received a copy of the GNU General Public License
019 * along with this program; if not, see <http://www.gnu.org/licenses>.
020 */
021 package com.unboundid.asn1;
022
023
024
025 import java.util.ArrayList;
026 import java.util.Collection;
027
028 import com.unboundid.util.ByteStringBuffer;
029 import com.unboundid.util.NotMutable;
030 import com.unboundid.util.ThreadSafety;
031 import com.unboundid.util.ThreadSafetyLevel;
032
033 import static com.unboundid.asn1.ASN1Constants.*;
034 import static com.unboundid.asn1.ASN1Messages.*;
035 import static com.unboundid.util.Debug.*;
036
037
038
039 /**
040 * This class provides an ASN.1 sequence element, which is used to hold an
041 * ordered set of zero or more other elements (potentially including additional
042 * "envelope" element types like other sequences and/or sets).
043 */
044 @NotMutable()
045 @ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
046 public final class ASN1Sequence
047 extends ASN1Element
048 {
049 /**
050 * The serial version UID for this serializable class.
051 */
052 private static final long serialVersionUID = 7294248008273774906L;
053
054
055
056 /*
057 * NOTE: This class uses lazy initialization for the encoded value. The
058 * encoded value should only be needed by the getValue() method, which is used
059 * by ASN1Element.encode(). Even though this class is externally immutable,
060 * that does not by itself make it completely threadsafe, because weirdness in
061 * the Java memory model could allow the assignment to be performed out of
062 * order. By passing the value through a volatile variable any time the value
063 * is set other than in the constructor (which will always be safe) we ensure
064 * that this reordering cannot happen.
065 *
066 * In the majority of cases, passing the value through assignments to
067 * valueBytes through a volatile variable is much faster than declaring
068 * valueBytes itself to be volatile because a volatile variable cannot be held
069 * in CPU caches or registers and must only be accessed from memory visible to
070 * all threads. Since the value may be read much more often than it is
071 * written, passing it through a volatile variable rather than making it
072 * volatile directly can help avoid that penalty when possible.
073 */
074
075
076
077 // The set of ASN.1 elements contained in this sequence.
078 private final ASN1Element[] elements;
079
080 // The encoded representation of the value, if available.
081 private byte[] encodedValue;
082
083 // A volatile variable used to guard publishing the encodedValue array. See
084 // the note above to explain why this is needed.
085 private volatile byte[] encodedValueGuard;
086
087
088
089 /**
090 * Creates a new ASN.1 sequence with the default BER type and no encapsulated
091 * elements.
092 */
093 public ASN1Sequence()
094 {
095 super(UNIVERSAL_SEQUENCE_TYPE);
096
097 elements = NO_ELEMENTS;
098 encodedValue = NO_VALUE;
099 }
100
101
102
103 /**
104 * Creates a new ASN.1 sequence with the specified BER type and no
105 * encapsulated elements.
106 *
107 * @param type The BER type to use for this element.
108 */
109 public ASN1Sequence(final byte type)
110 {
111 super(type);
112
113 elements = NO_ELEMENTS;
114 encodedValue = NO_VALUE;
115 }
116
117
118
119 /**
120 * Creates a new ASN.1 sequence with the default BER type and the provided set
121 * of elements.
122 *
123 * @param elements The set of elements to include in this sequence.
124 */
125 public ASN1Sequence(final ASN1Element... elements)
126 {
127 super(UNIVERSAL_SEQUENCE_TYPE);
128
129 if (elements == null)
130 {
131 this.elements = NO_ELEMENTS;
132 }
133 else
134 {
135 this.elements = elements;
136 }
137
138 encodedValue = null;
139 }
140
141
142
143 /**
144 * Creates a new ASN.1 sequence with the default BER type and the provided set
145 * of elements.
146 *
147 * @param elements The set of elements to include in this sequence.
148 */
149 public ASN1Sequence(final Collection<? extends ASN1Element> elements)
150 {
151 super(UNIVERSAL_SEQUENCE_TYPE);
152
153 if ((elements == null) || elements.isEmpty())
154 {
155 this.elements = NO_ELEMENTS;
156 }
157 else
158 {
159 this.elements = new ASN1Element[elements.size()];
160 elements.toArray(this.elements);
161 }
162
163 encodedValue = null;
164 }
165
166
167
168 /**
169 * Creates a new ASN.1 sequence with the specified BER type and the provided
170 * set of elements.
171 *
172 * @param type The BER type to use for this element.
173 * @param elements The set of elements to include in this sequence.
174 */
175 public ASN1Sequence(final byte type, final ASN1Element... elements)
176 {
177 super(type);
178
179 if (elements == null)
180 {
181 this.elements = NO_ELEMENTS;
182 }
183 else
184 {
185 this.elements = elements;
186 }
187
188 encodedValue = null;
189 }
190
191
192
193 /**
194 * Creates a new ASN.1 sequence with the specified BER type and the provided
195 * set of elements.
196 *
197 * @param type The BER type to use for this element.
198 * @param elements The set of elements to include in this sequence.
199 */
200 public ASN1Sequence(final byte type,
201 final Collection<? extends ASN1Element> elements)
202 {
203 super(type);
204
205 if ((elements == null) || elements.isEmpty())
206 {
207 this.elements = NO_ELEMENTS;
208 }
209 else
210 {
211 this.elements = new ASN1Element[elements.size()];
212 elements.toArray(this.elements);
213 }
214
215 encodedValue = null;
216 }
217
218
219
220 /**
221 * Creates a new ASN.1 sequence with the specified type, set of elements, and
222 * encoded value.
223 *
224 * @param type The BER type to use for this element.
225 * @param elements The set of elements to include in this sequence.
226 * @param value The pre-encoded value for this element.
227 */
228 private ASN1Sequence(final byte type, final ASN1Element[] elements,
229 final byte[] value)
230 {
231 super(type);
232
233 this.elements = elements;
234 encodedValue = value;
235 }
236
237
238
239 /**
240 * {@inheritDoc}
241 */
242 @Override()
243 byte[] getValueArray()
244 {
245 return getValue();
246 }
247
248
249
250 /**
251 * {@inheritDoc}
252 */
253 @Override()
254 int getValueOffset()
255 {
256 return 0;
257 }
258
259
260
261 /**
262 * {@inheritDoc}
263 */
264 @Override()
265 public int getValueLength()
266 {
267 return getValue().length;
268 }
269
270
271
272 /**
273 * {@inheritDoc}
274 */
275 @Override()
276 public byte[] getValue()
277 {
278 if (encodedValue == null)
279 {
280 encodedValueGuard = encodeElements(elements);
281 encodedValue = encodedValueGuard;
282 }
283
284 return encodedValue;
285 }
286
287
288
289 /**
290 * {@inheritDoc}
291 */
292 @Override()
293 public void encodeTo(final ByteStringBuffer buffer)
294 {
295 buffer.append(getType());
296
297 if (elements.length == 0)
298 {
299 buffer.append((byte) 0x00);
300 return;
301 }
302
303 // In this case, it will likely be faster to just go ahead and append
304 // encoded representations of all of the elements and insert the length
305 // later once we know it.
306 final int originalLength = buffer.length();
307 for (final ASN1Element e : elements)
308 {
309 e.encodeTo(buffer);
310 }
311
312 buffer.insert(originalLength,
313 encodeLength(buffer.length() - originalLength));
314 }
315
316
317
318 /**
319 * Encodes the provided set of elements to a byte array suitable for use as
320 * the element value.
321 *
322 * @param elements The set of elements to be encoded.
323 *
324 * @return A byte array containing the encoded elements.
325 */
326 static byte[] encodeElements(final ASN1Element[] elements)
327 {
328 if ((elements == null) || (elements.length == 0))
329 {
330 return NO_VALUE;
331 }
332
333 int totalLength = 0;
334 final int numElements = elements.length;
335 final byte[][] encodedElements = new byte[numElements][];
336 for (int i=0; i < numElements; i++)
337 {
338 encodedElements[i] = elements[i].encode();
339 totalLength += encodedElements[i].length;
340 }
341
342 int pos = 0;
343 final byte[] b = new byte[totalLength];
344 for (int i=0; i < numElements; i++)
345 {
346 System.arraycopy(encodedElements[i], 0, b, pos,
347 encodedElements[i].length);
348 pos += encodedElements[i].length;
349 }
350
351 return b;
352 }
353
354
355
356 /**
357 * Retrieves the set of encapsulated elements held in this sequence.
358 *
359 * @return The set of encapsulated elements held in this sequence.
360 */
361 public ASN1Element[] elements()
362 {
363 return elements;
364 }
365
366
367
368 /**
369 * Decodes the contents of the provided byte array as a sequence element.
370 *
371 * @param elementBytes The byte array to decode as an ASN.1 sequence
372 * element.
373 *
374 * @return The decoded ASN.1 sequence element.
375 *
376 * @throws ASN1Exception If the provided array cannot be decoded as a
377 * sequence element.
378 */
379 public static ASN1Sequence decodeAsSequence(final byte[] elementBytes)
380 throws ASN1Exception
381 {
382 try
383 {
384 int valueStartPos = 2;
385 int length = (elementBytes[1] & 0x7F);
386 if (length != elementBytes[1])
387 {
388 final int numLengthBytes = length;
389
390 length = 0;
391 for (int i=0; i < numLengthBytes; i++)
392 {
393 length <<= 8;
394 length |= (elementBytes[valueStartPos++] & 0xFF);
395 }
396 }
397
398 if ((elementBytes.length - valueStartPos) != length)
399 {
400 throw new ASN1Exception(ERR_ELEMENT_LENGTH_MISMATCH.get(length,
401 (elementBytes.length - valueStartPos)));
402 }
403
404 final byte[] value = new byte[length];
405 System.arraycopy(elementBytes, valueStartPos, value, 0, length);
406
407 int numElements = 0;
408 final ArrayList<ASN1Element> elementList = new ArrayList<ASN1Element>(5);
409 try
410 {
411 int pos = 0;
412 while (pos < value.length)
413 {
414 final byte type = value[pos++];
415
416 final byte firstLengthByte = value[pos++];
417 int l = (firstLengthByte & 0x7F);
418 if (l != firstLengthByte)
419 {
420 final int numLengthBytes = l;
421 l = 0;
422 for (int i=0; i < numLengthBytes; i++)
423 {
424 l <<= 8;
425 l |= (value[pos++] & 0xFF);
426 }
427 }
428
429 final int posPlusLength = pos + l;
430 if ((l < 0) || (posPlusLength < 0) || (posPlusLength > value.length))
431 {
432 throw new ASN1Exception(
433 ERR_SEQUENCE_BYTES_DECODE_LENGTH_EXCEEDS_AVAILABLE.get());
434 }
435
436 elementList.add(new ASN1Element(type, value, pos, l));
437 pos += l;
438 numElements++;
439 }
440 }
441 catch (final ASN1Exception ae)
442 {
443 throw ae;
444 }
445 catch (final Exception e)
446 {
447 debugException(e);
448 throw new ASN1Exception(ERR_SEQUENCE_BYTES_DECODE_EXCEPTION.get(e), e);
449 }
450
451 int i = 0;
452 final ASN1Element[] elements = new ASN1Element[numElements];
453 for (final ASN1Element e : elementList)
454 {
455 elements[i++] = e;
456 }
457
458 return new ASN1Sequence(elementBytes[0], elements, value);
459 }
460 catch (final ASN1Exception ae)
461 {
462 debugException(ae);
463 throw ae;
464 }
465 catch (final Exception e)
466 {
467 debugException(e);
468 throw new ASN1Exception(ERR_ELEMENT_DECODE_EXCEPTION.get(e), e);
469 }
470 }
471
472
473
474 /**
475 * Decodes the provided ASN.1 element as a sequence element.
476 *
477 * @param element The ASN.1 element to be decoded.
478 *
479 * @return The decoded ASN.1 sequence element.
480 *
481 * @throws ASN1Exception If the provided element cannot be decoded as a
482 * sequence element.
483 */
484 public static ASN1Sequence decodeAsSequence(final ASN1Element element)
485 throws ASN1Exception
486 {
487 int numElements = 0;
488 final ArrayList<ASN1Element> elementList = new ArrayList<ASN1Element>(5);
489 final byte[] value = element.getValue();
490
491 try
492 {
493 int pos = 0;
494 while (pos < value.length)
495 {
496 final byte type = value[pos++];
497
498 final byte firstLengthByte = value[pos++];
499 int length = (firstLengthByte & 0x7F);
500 if (length != firstLengthByte)
501 {
502 final int numLengthBytes = length;
503 length = 0;
504 for (int i=0; i < numLengthBytes; i++)
505 {
506 length <<= 8;
507 length |= (value[pos++] & 0xFF);
508 }
509 }
510
511 final int posPlusLength = pos + length;
512 if ((length < 0) || (posPlusLength < 0) ||
513 (posPlusLength > value.length))
514 {
515 throw new ASN1Exception(
516 ERR_SEQUENCE_DECODE_LENGTH_EXCEEDS_AVAILABLE.get(
517 String.valueOf(element)));
518 }
519
520 elementList.add(new ASN1Element(type, value, pos, length));
521 pos += length;
522 numElements++;
523 }
524 }
525 catch (final ASN1Exception ae)
526 {
527 throw ae;
528 }
529 catch (final Exception e)
530 {
531 debugException(e);
532 throw new ASN1Exception(
533 ERR_SEQUENCE_DECODE_EXCEPTION.get(String.valueOf(element), e), e);
534 }
535
536 int i = 0;
537 final ASN1Element[] elements = new ASN1Element[numElements];
538 for (final ASN1Element e : elementList)
539 {
540 elements[i++] = e;
541 }
542
543 return new ASN1Sequence(element.getType(), elements, value);
544 }
545
546
547
548 /**
549 * Appends a string representation of this ASN.1 element to the provided
550 * buffer.
551 *
552 * @param buffer The buffer to which to append the information.
553 */
554 @Override()
555 public void toString(final StringBuilder buffer)
556 {
557 buffer.append('[');
558 for (int i=0; i < elements.length; i++)
559 {
560 if (i > 0)
561 {
562 buffer.append(',');
563 }
564 elements[i].toString(buffer);
565 }
566 buffer.append(']');
567 }
568 }