001/*
002 * Copyright 2017-2018 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright (C) 2017-2018 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.Debug;
026import com.unboundid.util.NotMutable;
027import com.unboundid.util.StaticUtils;
028import com.unboundid.util.ThreadSafety;
029import com.unboundid.util.ThreadSafetyLevel;
030
031import static com.unboundid.asn1.ASN1Messages.*;
032
033
034
035/**
036 * This class provides an ASN.1 IA5 string element that can hold any empty or
037 * non-empty string comprised only of the ASCII characters (including ASCII
038 * control characters).
039 */
040@NotMutable()
041@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
042public final class ASN1IA5String
043       extends ASN1Element
044{
045  /**
046   * The serial version UID for this serializable class.
047   */
048  private static final long serialVersionUID = -9112411497688179053L;
049
050
051
052  // The string value for this element.
053  private final String stringValue;
054
055
056
057  /**
058   * Creates a new ASN.1 IA5 string element with the default BER type and the
059   * provided value.
060   *
061   * @param  stringValue  The string value to use for this element.  It may be
062   *                      {@code null} or empty if the value should be empty.
063   *                      It must only contain characters from the ASCII
064   *                      character set (including control characters).
065   *
066   * @throws  ASN1Exception  If the provided string does not represent a valid
067   *                         IA5 string.
068   */
069  public ASN1IA5String(final String stringValue)
070         throws ASN1Exception
071  {
072    this(ASN1Constants.UNIVERSAL_IA5_STRING_TYPE, stringValue);
073  }
074
075
076
077  /**
078   * Creates a new ASN.1 IA5 string element with the specified BER type and the
079   * provided value.
080   *
081   * @param  type         The BER type for this element.
082   * @param  stringValue  The string value to use for this element.  It may be
083   *                      {@code null} or empty if the value should be empty.
084   *                      It must only contain characters from the ASCII
085   *                      character set (including control characters).
086   *
087   * @throws  ASN1Exception  If the provided string does not represent a valid
088   *                         IA5 string.
089   */
090  public ASN1IA5String(final byte type, final String stringValue)
091         throws ASN1Exception
092  {
093    this(type, stringValue, StaticUtils.getBytes(stringValue));
094  }
095
096
097
098  /**
099   * Creates a new ASN.1 IA5 string element with the specified BER type and the
100   * provided value.
101   *
102   * @param  type          The BER type for this element.
103   * @param  stringValue   The string value to use for this element.  It may be
104   *                       {@code null} or empty if the value should be empty.
105   *                       It must only contain characters from the ASCII
106   *                       character set (including control characters).
107   * @param  encodedValue  The bytes that comprise the encoded element value.
108   *
109   * @throws  ASN1Exception  If the provided string does not represent a valid
110   *                         IA5 string.
111   */
112  private ASN1IA5String(final byte type, final String stringValue,
113                        final byte[] encodedValue)
114          throws ASN1Exception
115  {
116    super(type, encodedValue);
117
118    if (stringValue == null)
119    {
120      this.stringValue = "";
121    }
122    else
123    {
124      this.stringValue = stringValue;
125
126      for (final byte b : encodedValue)
127      {
128        if ((b & 0x7F) != (b & 0xFF))
129        {
130          throw new ASN1Exception(ERR_IA5_STRING_DECODE_VALUE_NOT_IA5.get());
131        }
132      }
133    }
134  }
135
136
137
138  /**
139   * Retrieves the string value for this element.
140   *
141   * @return  The string value for this element.
142   */
143  public String stringValue()
144  {
145    return stringValue;
146  }
147
148
149
150  /**
151   * Decodes the contents of the provided byte array as an IA5 string element.
152   *
153   * @param  elementBytes  The byte array to decode as an ASN.1 IA5 string
154   *                       element.
155   *
156   * @return  The decoded ASN.1 IA5 string element.
157   *
158   * @throws  ASN1Exception  If the provided array cannot be decoded as an
159   *                         IA5 string element.
160   */
161  public static ASN1IA5String decodeAsIA5String(final byte[] elementBytes)
162         throws ASN1Exception
163  {
164    try
165    {
166      int valueStartPos = 2;
167      int length = (elementBytes[1] & 0x7F);
168      if (length != elementBytes[1])
169      {
170        final int numLengthBytes = length;
171
172        length = 0;
173        for (int i=0; i < numLengthBytes; i++)
174        {
175          length <<= 8;
176          length |= (elementBytes[valueStartPos++] & 0xFF);
177        }
178      }
179
180      if ((elementBytes.length - valueStartPos) != length)
181      {
182        throw new ASN1Exception(ERR_ELEMENT_LENGTH_MISMATCH.get(length,
183                                     (elementBytes.length - valueStartPos)));
184      }
185
186      final byte[] elementValue = new byte[length];
187      System.arraycopy(elementBytes, valueStartPos, elementValue, 0, length);
188
189      return new ASN1IA5String(elementBytes[0],
190           StaticUtils.toUTF8String(elementValue), elementValue);
191    }
192    catch (final ASN1Exception ae)
193    {
194      Debug.debugException(ae);
195      throw ae;
196    }
197    catch (final Exception e)
198    {
199      Debug.debugException(e);
200      throw new ASN1Exception(ERR_ELEMENT_DECODE_EXCEPTION.get(e), e);
201    }
202  }
203
204
205
206  /**
207   * Decodes the provided ASN.1 element as an IA5 string element.
208   *
209   * @param  element  The ASN.1 element to be decoded.
210   *
211   * @return  The decoded ASN.1 IA5 string element.
212   *
213   * @throws  ASN1Exception  If the provided element cannot be decoded as an
214   *                         IA5 string element.
215   */
216  public static ASN1IA5String decodeAsIA5String(final ASN1Element element)
217         throws ASN1Exception
218  {
219    final byte[] elementValue = element.getValue();
220    return new ASN1IA5String(element.getType(),
221         StaticUtils.toUTF8String(elementValue), elementValue);
222  }
223
224
225
226  /**
227   * {@inheritDoc}
228   */
229  @Override()
230  public void toString(final StringBuilder buffer)
231  {
232    buffer.append(stringValue);
233  }
234}