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