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