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 UTF-8 string element that can hold any string 038 * value that can be represented in the UTF-8 encoding. 039 */ 040@NotMutable() 041@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 042public final class ASN1UTF8String 043 extends ASN1Element 044{ 045 /** 046 * The serial version UID for this serializable class. 047 */ 048 private static final long serialVersionUID = -2147537370903003997L; 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 UTF-8 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 */ 064 public ASN1UTF8String(final String stringValue) 065 { 066 this(UNIVERSAL_UTF_8_STRING_TYPE, stringValue); 067 } 068 069 070 071 /** 072 * Creates a new ASN.1 UTF-8 string element with the specified BER type and 073 * the provided value. 074 * 075 * @param type The BER type for this element. 076 * @param stringValue The string value to use for this element. It may be 077 * {@code null} or empty if the value should be empty. 078 */ 079 public ASN1UTF8String(final byte type, final String stringValue) 080 { 081 this(type, stringValue, StaticUtils.getBytes(stringValue)); 082 } 083 084 085 086 /** 087 * Creates a new ASN.1 UTF-8 string element with the specified BER type and 088 * the provided value. 089 * 090 * @param type The BER type for this element. 091 * @param stringValue The string value to use for this element. It may be 092 * {@code null} or empty if the value should be empty. 093 * @param encodedValue The encoded representation of the value. 094 */ 095 private ASN1UTF8String(final byte type, final String stringValue, 096 final byte[] encodedValue) 097 { 098 super(type, encodedValue); 099 100 if (stringValue == null) 101 { 102 this.stringValue = ""; 103 } 104 else 105 { 106 this.stringValue = stringValue; 107 } 108 } 109 110 111 112 /** 113 * Retrieves the string value for this element. 114 * 115 * @return The string value for this element. 116 */ 117 public String stringValue() 118 { 119 return stringValue; 120 } 121 122 123 124 /** 125 * Decodes the contents of the provided byte array as a UTF-8 string element. 126 * 127 * @param elementBytes The byte array to decode as an ASN.1 UTF-8 string 128 * element. 129 * 130 * @return The decoded ASN.1 UTF-8 string element. 131 * 132 * @throws ASN1Exception If the provided array cannot be decoded as a UTF-8 133 * string element. 134 */ 135 public static ASN1UTF8String decodeAsUTF8String(final byte[] elementBytes) 136 throws ASN1Exception 137 { 138 try 139 { 140 int valueStartPos = 2; 141 int length = (elementBytes[1] & 0x7F); 142 if (length != elementBytes[1]) 143 { 144 final int numLengthBytes = length; 145 146 length = 0; 147 for (int i=0; i < numLengthBytes; i++) 148 { 149 length <<= 8; 150 length |= (elementBytes[valueStartPos++] & 0xFF); 151 } 152 } 153 154 if ((elementBytes.length - valueStartPos) != length) 155 { 156 throw new ASN1Exception(ERR_ELEMENT_LENGTH_MISMATCH.get(length, 157 (elementBytes.length - valueStartPos))); 158 } 159 160 final byte[] elementValue = new byte[length]; 161 System.arraycopy(elementBytes, valueStartPos, elementValue, 0, length); 162 163 if (! StaticUtils.isValidUTF8(elementValue)) 164 { 165 throw new ASN1Exception(ERR_UTF_8_STRING_DECODE_VALUE_NOT_UTF_8.get()); 166 } 167 168 return new ASN1UTF8String(elementBytes[0], 169 StaticUtils.toUTF8String(elementValue), elementValue); 170 } 171 catch (final ASN1Exception ae) 172 { 173 debugException(ae); 174 throw ae; 175 } 176 catch (final Exception e) 177 { 178 debugException(e); 179 throw new ASN1Exception(ERR_ELEMENT_DECODE_EXCEPTION.get(e), e); 180 } 181 } 182 183 184 185 /** 186 * Decodes the provided ASN.1 element as a UTF-8 string element. 187 * 188 * @param element The ASN.1 element to be decoded. 189 * 190 * @return The decoded ASN.1 UTF-8 string element. 191 * 192 * @throws ASN1Exception If the provided element cannot be decoded as a 193 * UTF-8 string element. 194 */ 195 public static ASN1UTF8String decodeAsUTF8String(final ASN1Element element) 196 throws ASN1Exception 197 { 198 final byte[] elementValue = element.getValue(); 199 if (! StaticUtils.isValidUTF8(elementValue)) 200 { 201 throw new ASN1Exception(ERR_UTF_8_STRING_DECODE_VALUE_NOT_UTF_8.get()); 202 } 203 204 return new ASN1UTF8String(element.getType(), 205 StaticUtils.toUTF8String(elementValue), elementValue); 206 } 207 208 209 210 /** 211 * {@inheritDoc} 212 */ 213 @Override() 214 public void toString(final StringBuilder buffer) 215 { 216 buffer.append(stringValue); 217 } 218}