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