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