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 printable string element that can hold any 037 * empty or non-empty string comprised only of the characters listed below. 038 * <UL> 039 * <LI>The uppercase ASCII letters A through Z.</LI> 040 * <LI>The lowercase ASCII letters a through z.</LI> 041 * <LI>The ASCII digits 0 through 9.</LI> 042 * <LI>The ASCII space.</LI> 043 * <LI>The ASCII apostrophe (aka single quote).</LI> 044 * <LI>The ASCII left parenthesis.</LI> 045 * <LI>The ASCII right parenthesis.</LI> 046 * <LI>The ASCII plus sign.</LI> 047 * <LI>The ASCII comma.</LI> 048 * <LI>The ASCII minus sign (aka hyphen).</LI> 049 * <LI>The ASCII period (aka full stop).</LI> 050 * <LI>The ASCII forward slash (aka solidus).</LI> 051 * <LI>The ASCII colon.</LI> 052 * <LI>The ASCII equal sign.</LI> 053 * <LI>The ASCII question mark.</LI> 054 * </UL> 055 */ 056@NotMutable() 057@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 058public final class ASN1PrintableString 059 extends ASN1Element 060{ 061 /** 062 * The serial version UID for this serializable class. 063 */ 064 private static final long serialVersionUID = 7489436088285132189L; 065 066 067 068 // The string value for this element. 069 private final String stringValue; 070 071 072 073 /** 074 * Creates a new ASN.1 printable string element with the default BER type and 075 * the provided value. 076 * 077 * @param stringValue The string value to use for this element. It may be 078 * {@code null} or empty if the value should be empty. 079 * It must only contain characters allowed in printable 080 * strings. 081 * 082 * @throws ASN1Exception If the provided string does not represent a valid 083 * printable string. 084 */ 085 public ASN1PrintableString(final String stringValue) 086 throws ASN1Exception 087 { 088 this(ASN1Constants.UNIVERSAL_PRINTABLE_STRING_TYPE, stringValue); 089 } 090 091 092 093 /** 094 * Creates a new ASN.1 printable string element with the specified BER type 095 * and the provided value. 096 * 097 * @param type The BER type for this element. 098 * @param stringValue The string value to use for this element. It may be 099 * {@code null} or empty if the value should be empty. 100 * It must only contain characters allowed in printable 101 * strings. 102 * 103 * @throws ASN1Exception If the provided string does not represent a valid 104 * printable string. 105 */ 106 public ASN1PrintableString(final byte type, final String stringValue) 107 throws ASN1Exception 108 { 109 this(type, stringValue, StaticUtils.getBytes(stringValue)); 110 } 111 112 113 114 /** 115 * Creates a new ASN.1 printable string element with the specified BER type 116 * and the provided value. 117 * 118 * @param type The BER type for this element. 119 * @param stringValue The string value to use for this element. It may be 120 * {@code null} or empty if the value should be empty. 121 * It must only contain characters allowed in printable 122 * strings. 123 * @param encodedValue The bytes that comprise the encoded element value. 124 * 125 * @throws ASN1Exception If the provided string does not represent a valid 126 * printable string. 127 */ 128 private ASN1PrintableString(final byte type, final String stringValue, 129 final byte[] encodedValue) 130 throws ASN1Exception 131 { 132 super(type, encodedValue); 133 134 if (stringValue == null) 135 { 136 this.stringValue = ""; 137 } 138 else 139 { 140 this.stringValue = stringValue; 141 if (! StaticUtils.isPrintableString(encodedValue)) 142 { 143 throw new ASN1Exception( 144 ERR_PRINTABLE_STRING_DECODE_VALUE_NOT_PRINTABLE.get()); 145 } 146 } 147 } 148 149 150 151 /** 152 * Retrieves the string value for this element. 153 * 154 * @return The string value for this element. 155 */ 156 public String stringValue() 157 { 158 return stringValue; 159 } 160 161 162 163 /** 164 * Decodes the contents of the provided byte array as a printable string 165 * element. 166 * 167 * @param elementBytes The byte array to decode as an ASN.1 printable string 168 * element. 169 * 170 * @return The decoded ASN.1 printable string element. 171 * 172 * @throws ASN1Exception If the provided array cannot be decoded as a 173 * printable string element. 174 */ 175 public static ASN1PrintableString decodeAsPrintableString( 176 final byte[] elementBytes) 177 throws ASN1Exception 178 { 179 try 180 { 181 int valueStartPos = 2; 182 int length = (elementBytes[1] & 0x7F); 183 if (length != elementBytes[1]) 184 { 185 final int numLengthBytes = length; 186 187 length = 0; 188 for (int i=0; i < numLengthBytes; i++) 189 { 190 length <<= 8; 191 length |= (elementBytes[valueStartPos++] & 0xFF); 192 } 193 } 194 195 if ((elementBytes.length - valueStartPos) != length) 196 { 197 throw new ASN1Exception(ERR_ELEMENT_LENGTH_MISMATCH.get(length, 198 (elementBytes.length - valueStartPos))); 199 } 200 201 final byte[] elementValue = new byte[length]; 202 System.arraycopy(elementBytes, valueStartPos, elementValue, 0, length); 203 204 return new ASN1PrintableString(elementBytes[0], 205 StaticUtils.toUTF8String(elementValue), elementValue); 206 } 207 catch (final ASN1Exception ae) 208 { 209 Debug.debugException(ae); 210 throw ae; 211 } 212 catch (final Exception e) 213 { 214 Debug.debugException(e); 215 throw new ASN1Exception(ERR_ELEMENT_DECODE_EXCEPTION.get(e), e); 216 } 217 } 218 219 220 221 /** 222 * Decodes the provided ASN.1 element as a printable string element. 223 * 224 * @param element The ASN.1 element to be decoded. 225 * 226 * @return The decoded ASN.1 printable string element. 227 * 228 * @throws ASN1Exception If the provided element cannot be decoded as a 229 * printable string element. 230 */ 231 public static ASN1PrintableString decodeAsPrintableString( 232 final ASN1Element element) 233 throws ASN1Exception 234 { 235 final byte[] elementValue = element.getValue(); 236 return new ASN1PrintableString(element.getType(), 237 StaticUtils.toUTF8String(elementValue), elementValue); 238 } 239 240 241 242 /** 243 * {@inheritDoc} 244 */ 245 @Override() 246 public void toString(final StringBuilder buffer) 247 { 248 buffer.append(stringValue); 249 } 250}