001/* 002 * Copyright 2007-2018 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2008-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.ByteString; 026import com.unboundid.util.ByteStringBuffer; 027import com.unboundid.util.Debug; 028import com.unboundid.util.NotMutable; 029import com.unboundid.util.StaticUtils; 030import com.unboundid.util.ThreadSafety; 031import com.unboundid.util.ThreadSafetyLevel; 032import com.unboundid.util.Validator; 033 034import static com.unboundid.asn1.ASN1Messages.*; 035 036 037 038/** 039 * This class provides an ASN.1 octet string element, whose value is simply 040 * comprised of zero or more bytes. Octet string elements are frequently used 041 * to represent string values as well. 042 */ 043@NotMutable() 044@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 045public final class ASN1OctetString 046 extends ASN1Element 047 implements ByteString 048{ 049 /** 050 * The serial version UID for this serializable class. 051 */ 052 private static final long serialVersionUID = -7857753188341295516L; 053 054 055 056 /* 057 * NOTE: This class uses lazy initialization for the value. The value may 058 * be initially specified as either a string or a byte array, and if the value 059 * is provided as a string, then the byte array version of that value will be 060 * computed on-demand later. Even though this class is externally immutable, 061 * that does not by itself make it completely threadsafe, because weirdness in 062 * the Java memory model could allow the assignment to be performed out of 063 * order. By passing the value through a volatile variable any time the value 064 * is set other than in the constructor (which will always be safe) we ensure 065 * that this reordering cannot happen. This is only needed for the valueBytes 066 * array because it is not required for primitives (like length and offset) or 067 * for objects with only final fields (like stringValue). 068 * 069 * In the majority of cases, passing the value through a volatile variable is 070 * much faster than declaring valueBytes itself to be volatile because a 071 * volatile variable cannot be held in CPU caches or registers and must only 072 * be accessed from memory visible to all threads. Since the value may be 073 * read much more often than it is written, passing it through a volatile 074 * variable rather than making it volatile directly can help avoid that 075 * penalty when possible. 076 */ 077 078 079 080 // The binary representation of the value for this element. 081 private byte[] valueBytes; 082 083 // A volatile variable used to guard publishing the valueBytes array. See the 084 // note above to explain why this is needed. 085 private volatile byte[] valueBytesGuard; 086 087 // The length of the value in the byte array, if applicable. 088 private int length; 089 090 // The offset in the byte array at which the value begins, if applicable. 091 private int offset; 092 093 // The string representation of the value for this element. 094 private String stringValue; 095 096 097 098 /** 099 * Creates a new ASN.1 octet string element with the default BER type and 100 * no value. 101 */ 102 public ASN1OctetString() 103 { 104 super(ASN1Constants.UNIVERSAL_OCTET_STRING_TYPE); 105 106 valueBytes = StaticUtils.NO_BYTES; 107 stringValue = ""; 108 offset = 0; 109 length = 0; 110 } 111 112 113 114 /** 115 * Creates a new ASN.1 octet string element with the specified type and no 116 * value. 117 * 118 * @param type The BER type to use for this element. 119 */ 120 public ASN1OctetString(final byte type) 121 { 122 super(type); 123 124 valueBytes = StaticUtils.NO_BYTES; 125 stringValue = ""; 126 offset = 0; 127 length = 0; 128 } 129 130 131 132 /** 133 * Creates a new ASN.1 octet string element with the default BER type and the 134 * provided value. 135 * 136 * @param value The value to use for this element. 137 */ 138 public ASN1OctetString(final byte[] value) 139 { 140 super(ASN1Constants.UNIVERSAL_OCTET_STRING_TYPE); 141 142 if (value == null) 143 { 144 valueBytes = StaticUtils.NO_BYTES; 145 stringValue = ""; 146 offset = 0; 147 length = 0; 148 } 149 else 150 { 151 valueBytes = value; 152 stringValue = null; 153 offset = 0; 154 length = value.length; 155 } 156 } 157 158 159 160 /** 161 * Creates a new ASN.1 octet string element with the default BER type and the 162 * provided value. 163 * 164 * @param value The byte array containing the value to use for this 165 * element It must not be {@code null}. 166 * @param offset The offset within the array at which the value begins. It 167 * must be greater than or equal to zero and less than or 168 * equal to the length of the array. 169 * @param length The length in bytes of the value. It must be greater than 170 * or equal to zero, and it must not extend beyond the end of 171 * the array. 172 */ 173 public ASN1OctetString(final byte[] value, final int offset, final int length) 174 { 175 super(ASN1Constants.UNIVERSAL_OCTET_STRING_TYPE); 176 177 Validator.ensureNotNull(value); 178 Validator.ensureTrue((offset >= 0) && (length >= 0) && 179 (offset+length <= value.length)); 180 181 valueBytes = value; 182 stringValue = null; 183 this.offset = offset; 184 this.length = length; 185 } 186 187 188 189 /** 190 * Creates a new ASN.1 octet string element with the specified type and the 191 * provided value. 192 * 193 * @param type The BER type to use for this element. 194 * @param value The value to use for this element. 195 */ 196 public ASN1OctetString(final byte type, final byte[] value) 197 { 198 super(type); 199 200 if (value == null) 201 { 202 valueBytes = StaticUtils.NO_BYTES; 203 stringValue = ""; 204 offset = 0; 205 length = 0; 206 } 207 else 208 { 209 valueBytes = value; 210 stringValue = null; 211 offset = 0; 212 length = value.length; 213 } 214 } 215 216 217 218 /** 219 * Creates a new ASN.1 octet string element with the specified type and the 220 * provided value. 221 * 222 * @param type The BER type to use for this element. 223 * @param value The byte array containing the value to use for this 224 * element. It must not be {@code null}. 225 * @param offset The offset within the array at which the value begins. It 226 * must be greater than or equal to zero and less than or 227 * equal to the length of the array.. 228 * @param length The length in bytes of the value. It must be greater than 229 * or equal to zero, and it must not extend beyond the end of 230 * the array. 231 */ 232 public ASN1OctetString(final byte type, final byte[] value, final int offset, 233 final int length) 234 { 235 super(type); 236 237 Validator.ensureTrue((offset >= 0) && (length >= 0) && 238 (offset+length <= value.length)); 239 240 valueBytes = value; 241 stringValue = null; 242 this.offset = offset; 243 this.length = length; 244 } 245 246 247 248 /** 249 * Creates a new ASN.1 octet string element with the default BER type and the 250 * provided value. 251 * 252 * @param value The value to use for this element. 253 */ 254 public ASN1OctetString(final String value) 255 { 256 super(ASN1Constants.UNIVERSAL_OCTET_STRING_TYPE); 257 258 if (value == null) 259 { 260 valueBytes = StaticUtils.NO_BYTES; 261 stringValue = ""; 262 offset = 0; 263 length = 0; 264 } 265 else 266 { 267 valueBytes = null; 268 stringValue = value; 269 offset = -1; 270 length = -1; 271 } 272 } 273 274 275 276 /** 277 * Creates a new ASN.1 octet string element with the specified type and the 278 * provided value. 279 * 280 * @param type The BER type to use for this element. 281 * @param value The value to use for this element. 282 */ 283 public ASN1OctetString(final byte type, final String value) 284 { 285 super(type); 286 287 if (value == null) 288 { 289 valueBytes = StaticUtils.NO_BYTES; 290 stringValue = ""; 291 offset = 0; 292 length = 0; 293 } 294 else 295 { 296 valueBytes = null; 297 stringValue = value; 298 offset = -1; 299 length = -1; 300 } 301 } 302 303 304 305 /** 306 * {@inheritDoc} 307 */ 308 @Override() 309 byte[] getValueArray() 310 { 311 return getValue(); 312 } 313 314 315 316 /** 317 * {@inheritDoc} 318 */ 319 @Override() 320 int getValueOffset() 321 { 322 return 0; 323 } 324 325 326 327 /** 328 * {@inheritDoc} 329 */ 330 @Override() 331 public int getValueLength() 332 { 333 return getValue().length; 334 } 335 336 337 338 /** 339 * {@inheritDoc} 340 */ 341 @Override() 342 public byte[] getValue() 343 { 344 if (valueBytes == null) 345 { 346 valueBytesGuard = StaticUtils.getBytes(stringValue); 347 offset = 0; 348 length = valueBytesGuard.length; 349 valueBytes = valueBytesGuard; 350 } 351 else if ((offset != 0) || (length != valueBytes.length)) 352 { 353 final byte[] newArray = new byte[length]; 354 System.arraycopy(valueBytes, offset, newArray, 0, length); 355 offset = 0; 356 valueBytesGuard = newArray; 357 valueBytes = valueBytesGuard; 358 } 359 360 return valueBytes; 361 } 362 363 364 365 /** 366 * {@inheritDoc} 367 */ 368 @Override() 369 public void encodeTo(final ByteStringBuffer buffer) 370 { 371 buffer.append(getType()); 372 373 if (valueBytes == null) 374 { 375 // Assume that the string contains only ASCII characters. That will be 376 // true most of the time and we can optimize for it. If it's not true, 377 // then we'll fix it later. 378 final int stringLength = stringValue.length(); 379 final int lengthStartPos = buffer.length(); 380 encodeLengthTo(stringLength, buffer); 381 final int valueStartPos = buffer.length(); 382 buffer.append(stringValue); 383 final int stringBytesLength = buffer.length() - valueStartPos; 384 if (stringBytesLength != stringLength) 385 { 386 // This must mean that the string had non-ASCII characters in it, so 387 // fix the encoded representation. 388 final byte[] newLengthBytes = encodeLength(stringBytesLength); 389 if (newLengthBytes.length == (valueStartPos - lengthStartPos)) 390 { 391 // It takes the same number of bytes to encode the new length as 392 // the length we previously expected, so we can just overwrite the 393 // length bytes in the backing array. 394 System.arraycopy(newLengthBytes, 0, buffer.getBackingArray(), 395 lengthStartPos, newLengthBytes.length); 396 } 397 else 398 { 399 buffer.setLength(lengthStartPos); 400 buffer.append(newLengthBytes); 401 buffer.append(stringValue); 402 } 403 } 404 } 405 else 406 { 407 encodeLengthTo(length, buffer); 408 buffer.append(valueBytes, offset, length); 409 } 410 } 411 412 413 414 /** 415 * Retrieves the string value for this element. 416 * 417 * @return The String value for this element. 418 */ 419 @Override() 420 public String stringValue() 421 { 422 if (stringValue == null) 423 { 424 if (length == 0) 425 { 426 stringValue = ""; 427 } 428 else 429 { 430 stringValue = StaticUtils.toUTF8String(valueBytes, offset, length); 431 } 432 } 433 434 return stringValue; 435 } 436 437 438 439 /** 440 * Decodes the contents of the provided byte array as an octet string element. 441 * 442 * @param elementBytes The byte array to decode as an ASN.1 octet string 443 * element. 444 * 445 * @return The decoded ASN.1 octet string element. 446 * 447 * @throws ASN1Exception If the provided array cannot be decoded as an 448 * octet string element. 449 */ 450 public static ASN1OctetString decodeAsOctetString(final byte[] elementBytes) 451 throws ASN1Exception 452 { 453 try 454 { 455 int valueStartPos = 2; 456 int length = (elementBytes[1] & 0x7F); 457 if (length != elementBytes[1]) 458 { 459 final int numLengthBytes = length; 460 461 length = 0; 462 for (int i=0; i < numLengthBytes; i++) 463 { 464 length <<= 8; 465 length |= (elementBytes[valueStartPos++] & 0xFF); 466 } 467 } 468 469 if ((elementBytes.length - valueStartPos) != length) 470 { 471 throw new ASN1Exception(ERR_ELEMENT_LENGTH_MISMATCH.get(length, 472 (elementBytes.length - valueStartPos))); 473 } 474 475 return new ASN1OctetString(elementBytes[0], elementBytes, valueStartPos, 476 length); 477 } 478 catch (final ASN1Exception ae) 479 { 480 Debug.debugException(ae); 481 throw ae; 482 } 483 catch (final Exception e) 484 { 485 Debug.debugException(e); 486 throw new ASN1Exception(ERR_ELEMENT_DECODE_EXCEPTION.get(e), e); 487 } 488 } 489 490 491 492 /** 493 * Decodes the provided ASN.1 element as an octet string element. 494 * 495 * @param element The ASN.1 element to be decoded. 496 * 497 * @return The decoded ASN.1 octet string element. 498 */ 499 public static ASN1OctetString decodeAsOctetString(final ASN1Element element) 500 { 501 return new ASN1OctetString(element.getType(), element.getValue()); 502 } 503 504 505 506 /** 507 * Appends the value of this ASN.1 octet string to the provided buffer. 508 * 509 * @param buffer The buffer to which the value is to be appended. 510 */ 511 @Override() 512 public void appendValueTo(final ByteStringBuffer buffer) 513 { 514 if (valueBytes == null) 515 { 516 buffer.append(stringValue); 517 } 518 else 519 { 520 buffer.append(valueBytes, offset, length); 521 } 522 } 523 524 525 526 /** 527 * Converts this byte string to an ASN.1 octet string. 528 * 529 * @return An ASN.1 octet string with the value of this byte string. 530 */ 531 @Override() 532 public ASN1OctetString toASN1OctetString() 533 { 534 return this; 535 } 536 537 538 539 /** 540 * {@inheritDoc} 541 */ 542 @Override() 543 public void toString(final StringBuilder buffer) 544 { 545 buffer.append(stringValue()); 546 } 547}