001 /*
002 * Copyright 2007-2016 UnboundID Corp.
003 * All Rights Reserved.
004 */
005 /*
006 * Copyright (C) 2008-2016 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 com.unboundid.util.ByteString;
026 import com.unboundid.util.ByteStringBuffer;
027
028 import static com.unboundid.asn1.ASN1Constants.*;
029 import static com.unboundid.asn1.ASN1Messages.*;
030 import static com.unboundid.util.Debug.*;
031 import static com.unboundid.util.StaticUtils.*;
032 import static com.unboundid.util.Validator.*;
033
034
035
036 /**
037 * This class provides an ASN.1 octet string element, whose value is simply
038 * comprised of zero or more bytes. Octet string elements are frequently used
039 * to represent string values as well.
040 */
041 public final class ASN1OctetString
042 extends ASN1Element
043 implements ByteString
044 {
045 /**
046 * The serial version UID for this serializable class.
047 */
048 private static final long serialVersionUID = -7857753188341295516L;
049
050
051
052 /*
053 * NOTE: This class uses lazy initialization for the value. The value may
054 * be initially specified as either a string or a byte array, and if the value
055 * is provided as a string, then the byte array version of that value will be
056 * computed on-demand later. Even though this class is externally immutable,
057 * that does not by itself make it completely threadsafe, because weirdness in
058 * the Java memory model could allow the assignment to be performed out of
059 * order. By passing the value through a volatile variable any time the value
060 * is set other than in the constructor (which will always be safe) we ensure
061 * that this reordering cannot happen. This is only needed for the valueBytes
062 * array because it is not required for primitives (like length and offset) or
063 * for objects with only final fields (like stringValue).
064 *
065 * In the majority of cases, passing the value through a volatile variable is
066 * much faster than declaring valueBytes itself to be volatile because a
067 * volatile variable cannot be held in CPU caches or registers and must only
068 * be accessed from memory visible to all threads. Since the value may be
069 * read much more often than it is written, passing it through a volatile
070 * variable rather than making it volatile directly can help avoid that
071 * penalty when possible.
072 */
073
074
075
076 // The binary representation of the value for this element.
077 private byte[] valueBytes;
078
079 // A volatile variable used to guard publishing the valueBytes array. See the
080 // note above to explain why this is needed.
081 private volatile byte[] valueBytesGuard;
082
083 // The length of the value in the byte array, if applicable.
084 private int length;
085
086 // The offset in the byte array at which the value begins, if applicable.
087 private int offset;
088
089 // The string representation of the value for this element.
090 private String stringValue;
091
092
093
094 /**
095 * Creates a new ASN.1 octet string element with the default BER type and
096 * no value.
097 */
098 public ASN1OctetString()
099 {
100 super(UNIVERSAL_OCTET_STRING_TYPE);
101
102 valueBytes = NO_BYTES;
103 stringValue = "";
104 offset = 0;
105 length = 0;
106 }
107
108
109
110 /**
111 * Creates a new ASN.1 octet string element with the specified type and no
112 * value.
113 *
114 * @param type The BER type to use for this element.
115 */
116 public ASN1OctetString(final byte type)
117 {
118 super(type);
119
120 valueBytes = NO_BYTES;
121 stringValue = "";
122 offset = 0;
123 length = 0;
124 }
125
126
127
128 /**
129 * Creates a new ASN.1 octet string element with the default BER type and the
130 * provided value.
131 *
132 * @param value The value to use for this element.
133 */
134 public ASN1OctetString(final byte[] value)
135 {
136 super(UNIVERSAL_OCTET_STRING_TYPE);
137
138 if (value == null)
139 {
140 valueBytes = NO_BYTES;
141 stringValue = "";
142 offset = 0;
143 length = 0;
144 }
145 else
146 {
147 valueBytes = value;
148 stringValue = null;
149 offset = 0;
150 length = value.length;
151 }
152 }
153
154
155
156 /**
157 * Creates a new ASN.1 octet string element with the default BER type and the
158 * provided value.
159 *
160 * @param value The byte array containing the value to use for this
161 * element It must not be {@code null}.
162 * @param offset The offset within the array at which the value begins. It
163 * must be greater than or equal to zero and less than or
164 * equal to the length of the array.
165 * @param length The length in bytes of the value. It must be greater than
166 * or equal to zero, and it must not extend beyond the end of
167 * the array.
168 */
169 public ASN1OctetString(final byte[] value, final int offset, final int length)
170 {
171 super(UNIVERSAL_OCTET_STRING_TYPE);
172
173 ensureNotNull(value);
174 ensureTrue((offset >= 0) && (length >= 0) &&
175 (offset+length <= value.length));
176
177 valueBytes = value;
178 stringValue = null;
179 this.offset = offset;
180 this.length = length;
181 }
182
183
184
185 /**
186 * Creates a new ASN.1 octet string element with the specified type and the
187 * provided value.
188 *
189 * @param type The BER type to use for this element.
190 * @param value The value to use for this element.
191 */
192 public ASN1OctetString(final byte type, final byte[] value)
193 {
194 super(type);
195
196 if (value == null)
197 {
198 valueBytes = NO_BYTES;
199 stringValue = "";
200 offset = 0;
201 length = 0;
202 }
203 else
204 {
205 valueBytes = value;
206 stringValue = null;
207 offset = 0;
208 length = value.length;
209 }
210 }
211
212
213
214 /**
215 * Creates a new ASN.1 octet string element with the specified type and the
216 * provided value.
217 *
218 * @param type The BER type to use for this element.
219 * @param value The byte array containing the value to use for this
220 * element. It must not be {@code null}.
221 * @param offset The offset within the array at which the value begins. It
222 * must be greater than or equal to zero and less than or
223 * equal to the length of the array..
224 * @param length The length in bytes of the value. It must be greater than
225 * or equal to zero, and it must not extend beyond the end of
226 * the array.
227 */
228 public ASN1OctetString(final byte type, final byte[] value, final int offset,
229 final int length)
230 {
231 super(type);
232
233 ensureTrue((offset >= 0) && (length >= 0) &&
234 (offset+length <= value.length));
235
236 valueBytes = value;
237 stringValue = null;
238 this.offset = offset;
239 this.length = length;
240 }
241
242
243
244 /**
245 * Creates a new ASN.1 octet string element with the default BER type and the
246 * provided value.
247 *
248 * @param value The value to use for this element.
249 */
250 public ASN1OctetString(final String value)
251 {
252 super(UNIVERSAL_OCTET_STRING_TYPE);
253
254 if (value == null)
255 {
256 valueBytes = NO_BYTES;
257 stringValue = "";
258 offset = 0;
259 length = 0;
260 }
261 else
262 {
263 valueBytes = null;
264 stringValue = value;
265 offset = -1;
266 length = -1;
267 }
268 }
269
270
271
272 /**
273 * Creates a new ASN.1 octet string element with the specified type and the
274 * provided value.
275 *
276 * @param type The BER type to use for this element.
277 * @param value The value to use for this element.
278 */
279 public ASN1OctetString(final byte type, final String value)
280 {
281 super(type);
282
283 if (value == null)
284 {
285 valueBytes = NO_BYTES;
286 stringValue = "";
287 offset = 0;
288 length = 0;
289 }
290 else
291 {
292 valueBytes = null;
293 stringValue = value;
294 offset = -1;
295 length = -1;
296 }
297 }
298
299
300
301 /**
302 * {@inheritDoc}
303 */
304 @Override()
305 byte[] getValueArray()
306 {
307 return getValue();
308 }
309
310
311
312 /**
313 * {@inheritDoc}
314 */
315 @Override()
316 int getValueOffset()
317 {
318 return 0;
319 }
320
321
322
323 /**
324 * {@inheritDoc}
325 */
326 @Override()
327 public int getValueLength()
328 {
329 return getValue().length;
330 }
331
332
333
334 /**
335 * {@inheritDoc}
336 */
337 @Override()
338 public byte[] getValue()
339 {
340 if (valueBytes == null)
341 {
342 valueBytesGuard = getBytes(stringValue);
343 offset = 0;
344 length = valueBytesGuard.length;
345 valueBytes = valueBytesGuard;
346 }
347 else if ((offset != 0) || (length != valueBytes.length))
348 {
349 final byte[] newArray = new byte[length];
350 System.arraycopy(valueBytes, offset, newArray, 0, length);
351 offset = 0;
352 valueBytesGuard = newArray;
353 valueBytes = valueBytesGuard;
354 }
355
356 return valueBytes;
357 }
358
359
360
361 /**
362 * {@inheritDoc}
363 */
364 @Override()
365 public void encodeTo(final ByteStringBuffer buffer)
366 {
367 buffer.append(getType());
368
369 if (valueBytes == null)
370 {
371 // Assume that the string contains only ASCII characters. That will be
372 // true most of the time and we can optimize for it. If it's not true,
373 // then we'll fix it later.
374 final int stringLength = stringValue.length();
375 final int lengthStartPos = buffer.length();
376 encodeLengthTo(stringLength, buffer);
377 final int valueStartPos = buffer.length();
378 buffer.append(stringValue);
379 final int stringBytesLength = buffer.length() - valueStartPos;
380 if (stringBytesLength != stringLength)
381 {
382 // This must mean that the string had non-ASCII characters in it, so
383 // fix the encoded representation.
384 final byte[] newLengthBytes = encodeLength(stringBytesLength);
385 if (newLengthBytes.length == (valueStartPos - lengthStartPos))
386 {
387 // It takes the same number of bytes to encode the new length as
388 // the length we previously expected, so we can just overwrite the
389 // length bytes in the backing array.
390 System.arraycopy(newLengthBytes, 0, buffer.getBackingArray(),
391 lengthStartPos, newLengthBytes.length);
392 }
393 else
394 {
395 buffer.setLength(lengthStartPos);
396 buffer.append(newLengthBytes);
397 buffer.append(stringValue);
398 }
399 }
400 }
401 else
402 {
403 encodeLengthTo(length, buffer);
404 buffer.append(valueBytes, offset, length);
405 }
406 }
407
408
409
410 /**
411 * Retrieves the string value for this element.
412 *
413 * @return The String value for this element.
414 */
415 public String stringValue()
416 {
417 if (stringValue == null)
418 {
419 if (length == 0)
420 {
421 stringValue = "";
422 }
423 else
424 {
425 stringValue = toUTF8String(valueBytes, offset, length);
426 }
427 }
428
429 return stringValue;
430 }
431
432
433
434 /**
435 * Decodes the contents of the provided byte array as an octet string element.
436 *
437 * @param elementBytes The byte array to decode as an ASN.1 octet string
438 * element.
439 *
440 * @return The decoded ASN.1 octet string element.
441 *
442 * @throws ASN1Exception If the provided array cannot be decoded as an
443 * octet string element.
444 */
445 public static ASN1OctetString decodeAsOctetString(final byte[] elementBytes)
446 throws ASN1Exception
447 {
448 try
449 {
450 int valueStartPos = 2;
451 int length = (elementBytes[1] & 0x7F);
452 if (length != elementBytes[1])
453 {
454 final int numLengthBytes = length;
455
456 length = 0;
457 for (int i=0; i < numLengthBytes; i++)
458 {
459 length <<= 8;
460 length |= (elementBytes[valueStartPos++] & 0xFF);
461 }
462 }
463
464 if ((elementBytes.length - valueStartPos) != length)
465 {
466 throw new ASN1Exception(ERR_ELEMENT_LENGTH_MISMATCH.get(length,
467 (elementBytes.length - valueStartPos)));
468 }
469
470 return new ASN1OctetString(elementBytes[0], elementBytes, valueStartPos,
471 length);
472 }
473 catch (final ASN1Exception ae)
474 {
475 debugException(ae);
476 throw ae;
477 }
478 catch (final Exception e)
479 {
480 debugException(e);
481 throw new ASN1Exception(ERR_ELEMENT_DECODE_EXCEPTION.get(e), e);
482 }
483 }
484
485
486
487 /**
488 * Decodes the provided ASN.1 element as an octet string element.
489 *
490 * @param element The ASN.1 element to be decoded.
491 *
492 * @return The decoded ASN.1 octet string element.
493 */
494 public static ASN1OctetString decodeAsOctetString(final ASN1Element element)
495 {
496 return new ASN1OctetString(element.getType(), element.getValue());
497 }
498
499
500
501 /**
502 * Appends the value of this ASN.1 octet string to the provided buffer.
503 *
504 * @param buffer The buffer to which the value is to be appended.
505 */
506 public void appendValueTo(final ByteStringBuffer buffer)
507 {
508 if (valueBytes == null)
509 {
510 buffer.append(stringValue);
511 }
512 else
513 {
514 buffer.append(valueBytes, offset, length);
515 }
516 }
517
518
519
520 /**
521 * Converts this byte string to an ASN.1 octet string.
522 *
523 * @return An ASN.1 octet string with the value of this byte string.
524 */
525 public ASN1OctetString toASN1OctetString()
526 {
527 return this;
528 }
529
530
531
532 /**
533 * Appends a string representation of this ASN.1 element to the provided
534 * buffer.
535 *
536 * @param buffer The buffer to which to append the information.
537 */
538 @Override()
539 public void toString(final StringBuilder buffer)
540 {
541 buffer.append(stringValue());
542 }
543 }