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