001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * https://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 * 019 */ 020package org.apache.directory.api.asn1.util; 021 022 023import java.io.IOException; 024import java.io.OutputStream; 025import java.math.BigInteger; 026import java.nio.ByteBuffer; 027import java.util.Arrays; 028 029import org.apache.directory.api.asn1.DecoderException; 030import org.apache.directory.api.i18n.I18n; 031 032 033/** 034 * An immutable representation of an object identifier that provides conversion 035 * between their <code>String</code>, and encoded <code>byte[]</code> 036 * representations. 037 * 038 * <p> The encoding of OID values is performed according to 039 * <a href='http://www.itu.int/rec/T-REC-X.690/en'>itu X.690</a> section 8.19. 040 * Specifically:</p> 041 * 042 * <p><b>8.19.2</b> The contents octets shall be an (ordered) list of encodings 043 * of subidentifiers (see 8.19.3 and 8.19.4) concatenated together. Each 044 * subidentifier is represented as a series of (one or more) octets. Bit 8 of 045 * each octet indicates whether it is the last in the series: bit 8 of the last 046 * octet is zero; bit 8 of each preceding octet is one. Bits 7 to 1 of the 047 * octets in the series collectively encode the subidentifier. Conceptually, 048 * these groups of bits are concatenated to form an unsigned binary number whose 049 * most significant bit is bit 7 of the first octet and whose least significant 050 * bit is bit 1 of the last octet. The subidentifier shall be encoded in the 051 * fewest possible octets, that is, the leading octet of the subidentifier shall 052 * not have the value 0x80. </p> 053 * 054 * <p><b>8.19.3</b> The number of subidentifiers (N) shall be one less than the 055 * number of object identifier components in the object identifier value being 056 * encoded.</p> 057 * 058 * <p><b>8.19.4</b> The numerical value of the first subidentifier is derived 059 * from the values of the first two object identifier components in the object 060 * identifier value being encoded, using the formula: 061 * <br><code>(X*40) + Y</code><br> 062 * where X is the value of the first object identifier component and Y is the 063 * value of the second object identifier component. <i>NOTE – This packing of 064 * the first two object identifier components recognizes that only three values 065 * are allocated from the root node, and at most 39 subsequent values from nodes 066 * reached by X = 0 and X = 1.</i></p> 067 * 068 * <p>For example, the OID "2.12.3456.7" would be turned into a list of 3 values: 069 * <code>[((2*40)+12), 3456, 7]</code>. The first of which, 070 * <code>92</code>, would be encoded as the bytes <code>0x5C</code>, the second 071 * would be <code>[0x9B, 0x00]</code>, and the third as <code>0x07</code> 072 * giving the final encoding <code>[0x5C, 0x9B, 0x00, 0x07]</code>.</p> 073 * 074 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 075 */ 076public final class Oid 077{ 078 /** A byte[] representation of an OID */ 079 private byte[] oidBytes; 080 081 /** The OID as a String */ 082 private String oidString; 083 084 private static final BigInteger JOINT_ISO_ITU_T = BigInteger.valueOf( 80 ); 085 086 /** 087 * The OID FSA states. We have the following Finite State Automaton : 088 * 089 * <pre> 090 * (Start) --['0','1']--> (A) 091 * (start) --['2']--> (F) 092 * 093 * (A) --['.']--> (B) 094 * 095 * (B) --['0']--> (D) 096 * (B) --['1'..'3']--> (C) 097 * (B) --['4'..'9']--> (E) 098 * 099 * (C) --[]--> (End) 100 * (C) --['.']--> (K) 101 * (C) --['0'..'9']--> (E) 102 * 103 * (D) --[]--> (End) 104 * (D) --['.']--> (K) 105 * 106 * (E) --[]--> (End) 107 * (E) --['.']--> (K) 108 * 109 * (F) --['.']--> (G) 110 * 111 * (G) --['0']--> (I) 112 * (G) --['1'..'9']--> (H) 113 * 114 * (H) --[]--> (End) 115 * (H) --['.']--> (K) 116 * (H) --['0'..'9']--> (J) 117 * 118 * (I) --[]--> (End) 119 * (I) --['.']--> (K) 120 * 121 * (J) --[]--> (End) 122 * (J) --['.']--> (K) 123 * (J) --['0'..'9']--> (J) 124 * 125 * (K) --['0']--> (M) 126 * (K) --['1'..'9']--> (L) 127 * 128 * (L) --[]--> (End) 129 * (L) --['.']--> (K) 130 * (L) --['0'..'9']--> (L) 131 * 132 * (M) --[]--> (End) 133 * (M) --['.']--> (K) 134 * </pre> 135 */ 136 private enum OidFSAState 137 { 138 START, 139 STATE_A, 140 STATE_B, 141 STATE_C, 142 STATE_D, 143 STATE_E, 144 STATE_F, 145 STATE_G, 146 STATE_H, 147 STATE_I, 148 STATE_J, 149 STATE_K, 150 STATE_L, 151 STATE_M, 152 } 153 154 155 /** 156 * Creates a new instance of Oid. 157 * 158 * @param oidString The OID as a String 159 * @param oidBytes The OID as a byte[] 160 */ 161 private Oid( String oidString, byte[] oidBytes ) 162 { 163 this.oidString = oidString; 164 this.oidBytes = new byte[oidBytes.length]; 165 System.arraycopy( oidBytes, 0, this.oidBytes, 0, oidBytes.length ); 166 } 167 168 169 /** 170 * {@inheritDoc} 171 */ 172 @Override 173 public boolean equals( Object other ) 174 { 175 return ( other instanceof Oid ) 176 && oidString.equals( ( ( Oid ) other ).oidString ); 177 } 178 179 180 /** 181 * Decodes an OID from a <code>byte[]</code>. 182 * 183 * @param oidBytes The encoded<code>byte[]</code> 184 * @return A new Oid 185 * @throws DecoderException When the OID is not valid 186 */ 187 public static Oid fromBytes( byte[] oidBytes ) throws DecoderException 188 { 189 if ( ( oidBytes == null ) || ( oidBytes.length < 1 ) ) 190 { 191 throw new DecoderException( I18n.err( I18n.ERR_00003_INVALID_OID, Arrays.toString( oidBytes ) ) ); 192 } 193 194 StringBuilder builder = new StringBuilder(); 195 long value = 0; 196 int valStart = 0; 197 int valLength = 0; 198 boolean firstArc = true; 199 200 for ( int i = 0; i < oidBytes.length; i++ ) 201 { 202 value |= oidBytes[i] & 0x7F; 203 204 if ( oidBytes[i] < 0 ) 205 { 206 // leading 1, so value continues 207 value = value << 7; 208 valLength++; 209 } 210 else 211 { 212 valLength++; 213 214 if ( valLength > 8 ) 215 { 216 // Above 9 bytes, we won't be able to store the value in a long... 217 // Compute the number of necessary bytes 218 int nbBytes = valLength * 7 / 8; 219 220 if ( valLength % 7 != 0 ) 221 { 222 nbBytes++; 223 } 224 225 byte[] result = new byte[nbBytes]; 226 227 // Now iterate on the incoming bytes 228 int pos = nbBytes - 1; 229 int valEnd = valStart + valLength - 1; 230 int j = 0; 231 232 while ( j < valLength - 8 ) 233 { 234 result[pos--] = ( byte ) ( ( oidBytes[valEnd - j - 1] << 7 ) | ( oidBytes[valEnd - j] & 0x7F ) ); 235 result[pos--] = ( byte ) ( ( oidBytes[valEnd - j - 2] << 6 ) | ( ( oidBytes[valEnd - j - 1] & 0x7E ) >> 1 ) ); 236 result[pos--] = ( byte ) ( ( oidBytes[valEnd - j - 3] << 5 ) | ( ( oidBytes[valEnd - j - 2] & 0x7C ) >> 2 ) ); 237 result[pos--] = ( byte ) ( ( oidBytes[valEnd - j - 4] << 4 ) | ( ( oidBytes[valEnd - j - 3] & 0x78 ) >> 3 ) ); 238 result[pos--] = ( byte ) ( ( oidBytes[valEnd - j - 5] << 3 ) | ( ( oidBytes[valEnd - j - 4] & 0x70 ) >> 4 ) ); 239 result[pos--] = ( byte ) ( ( oidBytes[valEnd - j - 6] << 2 ) | ( ( oidBytes[valEnd - j - 5] & 0x60 ) >> 5 ) ); 240 result[pos--] = ( byte ) ( ( oidBytes[valEnd - j - 7] << 1 ) | ( ( oidBytes[valEnd - j - 6] & 0x40 ) >> 6 ) ); 241 j += 8; 242 } 243 244 switch ( valLength - j ) 245 { 246 case 7 : 247 result[pos--] = ( byte ) ( ( oidBytes[5] << 7 ) | ( oidBytes[6] & 0x7F ) ); 248 result[pos--] = ( byte ) ( ( oidBytes[4] << 6 ) | ( ( oidBytes[5] & 0x7E ) >> 1 ) ); 249 result[pos--] = ( byte ) ( ( oidBytes[3] << 5 ) | ( ( oidBytes[4] & 0x7C ) >> 2 ) ); 250 result[pos--] = ( byte ) ( ( oidBytes[2] << 4 ) | ( ( oidBytes[3] & 0x78 ) >> 3 ) ); 251 result[pos--] = ( byte ) ( ( oidBytes[1] << 3 ) | ( ( oidBytes[2] & 0x70 ) >> 4 ) ); 252 result[pos--] = ( byte ) ( ( oidBytes[0] << 2 ) | ( ( oidBytes[1] & 0x60 ) >> 5 ) ); 253 result[pos] = ( byte ) ( ( oidBytes[0] & 0x40 ) >> 6 ); 254 break; 255 256 case 6 : 257 result[pos--] = ( byte ) ( ( oidBytes[4] << 7 ) | ( oidBytes[5] & 0x7F ) ); 258 result[pos--] = ( byte ) ( ( oidBytes[3] << 6 ) | ( ( oidBytes[4] & 0x7E ) >> 1 ) ); 259 result[pos--] = ( byte ) ( ( oidBytes[2] << 5 ) | ( ( oidBytes[3] & 0x7C ) >> 2 ) ); 260 result[pos--] = ( byte ) ( ( oidBytes[1] << 4 ) | ( ( oidBytes[2] & 0x78 ) >> 3 ) ); 261 result[pos--] = ( byte ) ( ( oidBytes[0] << 3 ) | ( ( oidBytes[1] & 0x70 ) >> 4 ) ); 262 result[pos] = ( byte ) ( ( oidBytes[0] & 0x60 ) >> 5 ); 263 break; 264 265 case 5 : 266 result[pos--] = ( byte ) ( ( oidBytes[3] << 7 ) | ( oidBytes[4] & 0x7F ) ); 267 result[pos--] = ( byte ) ( ( oidBytes[2] << 6 ) | ( ( oidBytes[3] & 0x7E ) >> 1 ) ); 268 result[pos--] = ( byte ) ( ( oidBytes[1] << 5 ) | ( ( oidBytes[2] & 0x7C ) >> 2 ) ); 269 result[pos--] = ( byte ) ( ( oidBytes[0] << 4 ) | ( ( oidBytes[1] & 0x78 ) >> 3 ) ); 270 result[pos] = ( byte ) ( ( oidBytes[0] & 0x70 ) >> 4 ); 271 break; 272 273 case 4 : 274 result[pos--] = ( byte ) ( ( oidBytes[2] << 7 ) | ( oidBytes[3] & 0x7F ) ); 275 result[pos--] = ( byte ) ( ( oidBytes[1] << 6 ) | ( ( oidBytes[2] & 0x7E ) >> 1 ) ); 276 result[pos--] = ( byte ) ( ( oidBytes[0] << 5 ) | ( ( oidBytes[1] & 0x7C ) >> 2 ) ); 277 result[pos] = ( byte ) ( ( oidBytes[0] & 0x78 ) >> 3 ); 278 break; 279 280 case 3 : 281 result[pos--] = ( byte ) ( ( oidBytes[1] << 7 ) | ( oidBytes[2] & 0x7F ) ); 282 result[pos--] = ( byte ) ( ( oidBytes[0] << 6 ) | ( ( oidBytes[1] & 0x7E ) >> 1 ) ); 283 result[pos] = ( byte ) ( ( oidBytes[0] & 0x7C ) >> 2 ); 284 break; 285 286 case 2 : 287 result[pos--] = ( byte ) ( ( oidBytes[0] << 7 ) | ( oidBytes[1] & 0x7F ) ); 288 result[pos] = ( byte ) ( ( oidBytes[0] & 0x7E ) >> 1 ); 289 break; 290 291 case 1 : 292 result[pos] = ( byte ) ( oidBytes[0] & 0x7F ); 293 break; 294 295 default : 296 // Exist to please checkstyle... 297 break; 298 } 299 300 BigInteger bigInteger; 301 302 if ( ( result[0] & 0x80 ) == 0x80 ) 303 { 304 byte[] newResult = new byte[result.length + 1]; 305 System.arraycopy( result, 0, newResult, 1, result.length ); 306 result = newResult; 307 } 308 309 bigInteger = new BigInteger( result ); 310 311 if ( firstArc ) 312 { 313 // This is a joint-iso-itu-t(2) arc 314 bigInteger = bigInteger.subtract( JOINT_ISO_ITU_T ); 315 builder.append( '2' ); 316 } 317 318 builder.append( '.' ).append( bigInteger.toString() ); 319 } 320 else 321 { 322 // value completed 323 if ( firstArc ) 324 { 325 // first value special processing 326 if ( value >= 80 ) 327 { 328 // starts with 2 329 builder.append( '2' ); 330 value = value - 80; 331 } 332 else 333 { 334 // starts with 0 or 1 335 long one = value / 40; 336 long two = value % 40; 337 338 if ( ( one < 0 ) || ( one > 2 ) || ( two < 0 ) || ( ( one < 2 ) && ( two > 39 ) ) ) 339 { 340 throw new DecoderException( I18n.err( I18n.ERR_00003_INVALID_OID, 341 Arrays.toString( oidBytes ) ) ); 342 } 343 344 if ( one < 2 ) 345 { 346 builder.append( one ); 347 value = two; 348 } 349 } 350 351 firstArc = false; 352 } 353 354 // normal processing 355 builder.append( '.' ).append( value ); 356 } 357 358 valStart = i; 359 valLength = 0; 360 value = 0; 361 } 362 } 363 364 return new Oid( builder.toString(), oidBytes ); 365 } 366 367 368 /** 369 * Process state A 370 * <pre> 371 * (Start) --['0','1']--> (A) 372 * (start) --['2']--> (F) 373 * </pre> 374 * 375 * @param oid The OID to check 376 * @param buffer The buffer gathering the binary OID 377 * @param pos The position in the OID string 378 * @return The next OID decoding state 379 * @throws DecoderException If the OID is invalid 380 */ 381 private static OidFSAState processStateStart( String oid, byte[] buffer, int pos ) throws DecoderException 382 { 383 char c = oid.charAt( pos ); 384 385 switch ( c ) 386 { 387 case '0' : 388 case '1' : 389 buffer[0] = ( byte ) ( ( c - '0' ) * 40 ); 390 return OidFSAState.STATE_A; 391 392 case '2' : 393 return OidFSAState.STATE_F; 394 395 default : 396 // This is an error 397 throw new DecoderException( I18n.err( I18n.ERR_00003_INVALID_OID, "Should start with 0, 1 or 2" ) ); 398 } 399 } 400 401 402 /** 403 * Process state B 404 * <pre> 405 * (A) --['.']--> (B) 406 * </pre> 407 * 408 * @param oid The OID to check 409 * @param pos The position in the OID string 410 * @return The next OID decoding state 411 * @throws DecoderException If the OID is invalid 412 */ 413 private static OidFSAState processStateA( String oid, int pos ) throws DecoderException 414 { 415 if ( oid.charAt( pos ) != '.' ) 416 { 417 // Expecting a Dot here 418 throw new DecoderException( I18n.err( I18n.ERR_00003_INVALID_OID, "a '.' is expected" ) ); 419 } 420 421 return OidFSAState.STATE_B; 422 } 423 424 425 /** 426 * Process state B 427 * <pre> 428 * (B) --['0']--> (D) 429 * (B) --['1'..'3']--> (C) 430 * (B) --['4'..'9']--> (E) 431 * </pre> 432 * 433 * @param oid The OID to check 434 * @param buffer The buffer gathering the binary OID 435 * @param pos The position in the OID string 436 * @return The next OID decoding state 437 * @throws DecoderException If the OID is invalid 438 */ 439 private static OidFSAState processStateB( String oid, byte[] buffer, int pos ) throws DecoderException 440 { 441 char c = oid.charAt( pos ); 442 443 switch ( c ) 444 { 445 case '0' : 446 return OidFSAState.STATE_D; 447 448 case '1' : 449 case '2' : 450 case '3' : 451 // We may have a second digit. Atm, store the current one in the second psotion 452 buffer[1] = ( byte ) ( c - '0' ); 453 454 return OidFSAState.STATE_C; 455 456 case '4' : 457 case '5' : 458 case '6' : 459 case '7' : 460 case '8' : 461 case '9' : 462 buffer[0] += ( byte ) ( c - '0' ); 463 return OidFSAState.STATE_E; 464 465 default : 466 // Expecting a digit here 467 throw new DecoderException( I18n.err( I18n.ERR_00003_INVALID_OID, "a digit is expected" ) ); 468 } 469 } 470 471 472 /** 473 * Process state C 474 * <pre> 475 * (C) --['.']--> (K) 476 * (C) --['0'..'9']--> (E) 477 * </pre> 478 * 479 * @param oid The OID to check 480 * @param buffer The buffer gathering the binary OID 481 * @param pos The position in the OID string 482 * @return The next OID decoding state 483 * @throws DecoderException If the OID is invalid 484 */ 485 private static OidFSAState processStateC( String oid, byte[] buffer, int pos ) throws DecoderException 486 { 487 char c = oid.charAt( pos ); 488 489 switch ( c ) 490 { 491 case '0' : 492 case '1' : 493 case '2' : 494 case '3' : 495 case '4' : 496 case '5' : 497 case '6' : 498 case '7' : 499 case '8' : 500 case '9' : 501 buffer[0] += ( byte ) ( buffer[1] * 10 + ( c - '0' ) ); 502 buffer[1] = 0; 503 return OidFSAState.STATE_E; 504 505 case '.' : 506 buffer[0] += buffer[1]; 507 buffer[1] = 0; 508 return OidFSAState.STATE_K; 509 510 default : 511 // Expecting a digit here 512 throw new DecoderException( I18n.err( I18n.ERR_00003_INVALID_OID, "a digit is expected" ) ); 513 } 514 } 515 516 517 /** 518 * Process state D and E 519 * <pre> 520 * (D) --['.']--> (K) 521 * (E) --['.']--> (K) 522 * </pre> 523 * 524 * @param oid The OID to check 525 * @param buffer The buffer gathering the binary OID 526 * @param pos The position in the OID string 527 * @return The next OID decoding state 528 * @throws DecoderException If the OID is invalid 529 */ 530 private static OidFSAState processStateDE( String oid, byte[] buffer, int pos ) throws DecoderException 531 { 532 char c = oid.charAt( pos ); 533 534 if ( c != '.' ) 535 { 536 // Expecting a '.' here 537 throw new DecoderException( I18n.err( I18n.ERR_00003_INVALID_OID, "a dot is expected" ) ); 538 } 539 540 // Store the first byte into it 541 buffer[0] = ( byte ) ( buffer[0] | buffer[1] ); 542 buffer[1] = 0; 543 544 return OidFSAState.STATE_K; 545 } 546 547 548 /** 549 * Process state F 550 * <pre> 551 * (F) --['.']--> (G) 552 * </pre> 553 * 554 * @param oid The OID to check 555 * @param pos The position in the OID string 556 * @return The next OID decoding state 557 * @throws DecoderException If the OID is invalid 558 */ 559 private static OidFSAState processStateF( String oid, int pos ) throws DecoderException 560 { 561 if ( oid.charAt( pos ) != '.' ) 562 { 563 // Expecting a Dot here 564 throw new DecoderException( I18n.err( I18n.ERR_00003_INVALID_OID, "a '.' is expected" ) ); 565 } 566 567 return OidFSAState.STATE_G; 568 } 569 570 571 /** 572 * Process state G 573 * <pre> 574 * (G) --['0']--> (I) 575 * (G) --['1'..'9']--> (H) 576 * </pre> 577 * 578 * @param oid The OID to check 579 * @param buffer The buffer gathering the binary OID 580 * @param pos The position in the OID string 581 * @return The next OID decoding state 582 * @throws DecoderException If the OID is invalid 583 */ 584 private static OidFSAState processStateG( String oid, byte[] buffer, int pos ) throws DecoderException 585 { 586 char c = oid.charAt( pos ); 587 588 switch ( c ) 589 { 590 case '0' : 591 buffer[0] = ( byte ) 80; 592 return OidFSAState.STATE_I; 593 594 case '1' : 595 case '2' : 596 case '3' : 597 case '4' : 598 case '5' : 599 case '6' : 600 case '7' : 601 case '8' : 602 case '9' : 603 // Store the read digit in the second position in the buffer 604 buffer[0] = ( byte ) ( c - '0' ); 605 return OidFSAState.STATE_H; 606 607 default : 608 // Expecting a digit here 609 throw new DecoderException( I18n.err( I18n.ERR_00003_INVALID_OID, "a digit is expected" ) ); 610 } 611 } 612 613 614 /** 615 * Process state H 616 * <pre> 617 * (H) --['.']--> (K) 618 * (H) --['0'..'9']--> (J) 619 * </pre> 620 * 621 * @param oid The OID to check 622 * @param buffer The buffer gathering the binary OID 623 * @param pos The position in the OID string 624 * @return The next OID decoding state 625 * @throws DecoderException If the OID is invalid 626 */ 627 private static OidFSAState processStateH( String oid, byte[] buffer, int pos ) throws DecoderException 628 { 629 char c = oid.charAt( pos ); 630 631 switch ( c ) 632 { 633 case '0' : 634 case '1' : 635 case '2' : 636 case '3' : 637 case '4' : 638 case '5' : 639 case '6' : 640 case '7' : 641 case '8' : 642 case '9' : 643 // Store the read digit in the first position in the buffer 644 buffer[1] = ( byte ) ( c - '0' ); 645 return OidFSAState.STATE_J; 646 647 case '.' : 648 // The first 2 arcs are single digit, we can collapse them in one byte. 649 buffer[0] = ( byte ) ( 80 + buffer[0] ); 650 651 return OidFSAState.STATE_K; 652 653 default : 654 // Expecting a digit here 655 throw new DecoderException( I18n.err( I18n.ERR_00003_INVALID_OID, "a digit is expected" ) ); 656 } 657 } 658 659 660 /** 661 * Process state I 662 * <pre> 663 * (I) --['.']--> (K) 664 * </pre> 665 * 666 * @param oid The OID to check 667 * @param buffer The buffer gathering the binary OID 668 * @param pos The position in the OID string 669 * @return The next OID decoding state 670 * @throws DecoderException If the OID is invalid 671 */ 672 private static OidFSAState processStateI( String oid, byte[] buffer, int pos ) throws DecoderException 673 { 674 char c = oid.charAt( pos ); 675 676 if ( c == '.' ) 677 { 678 // The first 2 arcs are single digit, we can collapse them in one byte. 679 buffer[0] = ( byte ) ( 80 + buffer[1] ); 680 return OidFSAState.STATE_K; 681 } 682 else 683 { 684 // Expecting a digit here 685 throw new DecoderException( I18n.err( I18n.ERR_00003_INVALID_OID, "a digit is expected" ) ); 686 } 687 } 688 689 690 /** 691 * Process state J 692 * <pre> 693 * (J) --['.']--> (K) 694 * (J) --['0'..'9']--> (J) 695 * </pre> 696 * 697 * @param oid The OID to check 698 * @param buffer The buffer gathering the binary OID 699 * @param bufferPos The current position in the buffer 700 * @param pos The position in the OID string 701 * @return The next OID decoding state 702 * @throws DecoderException If the OID is invalid 703 */ 704 private static OidFSAState processStateJ( String oid, byte[] buffer, int bufferPos, int pos ) throws DecoderException 705 { 706 char c = oid.charAt( pos ); 707 708 switch ( c ) 709 { 710 case '.' : 711 return OidFSAState.STATE_K; 712 713 case '0' : 714 case '1' : 715 case '2' : 716 case '3' : 717 case '4' : 718 case '5' : 719 case '6' : 720 case '7' : 721 case '8' : 722 case '9' : 723 // Store the new digit at the right position in the buffer 724 buffer[bufferPos] = ( byte ) ( c - '0' ); 725 return OidFSAState.STATE_J; 726 727 default : 728 // Expecting a digit here 729 throw new DecoderException( I18n.err( I18n.ERR_00003_INVALID_OID, "a digit is expected" ) ); 730 } 731 } 732 733 734 /** 735 * Process state J 736 * <pre> 737 * (K) --['0']--> (M) 738 * (K) --['1'..'9']--> (L) 739 * </pre> 740 * 741 * @param oid The OID to check 742 * @param buffer The buffer gathering the binary OID 743 * @param bufferPos The current position in the buffer 744 * @param pos The position in the OID string 745 * @return The next OID decoding state 746 * @throws DecoderException If the OID is invalid 747 */ 748 private static OidFSAState processStateK( String oid, byte[] buffer, int bufferPos, int pos ) throws DecoderException 749 { 750 char c = oid.charAt( pos ); 751 752 switch ( c ) 753 { 754 case '0' : 755 buffer[bufferPos] = 0x00; 756 return OidFSAState.STATE_M; 757 758 case '1' : 759 case '2' : 760 case '3' : 761 case '4' : 762 case '5' : 763 case '6' : 764 case '7' : 765 case '8' : 766 case '9' : 767 // Store the new digit at the right position in the buffer 768 return OidFSAState.STATE_L; 769 770 default : 771 // Expecting a digit here 772 throw new DecoderException( I18n.err( I18n.ERR_00003_INVALID_OID, "a digit is expected" ) ); 773 } 774 } 775 776 777 /** 778 * Process state J 779 * <pre> 780 * (L) --['.']--> (K) 781 * (L) --['0'..'9']--> (L) 782 * </pre> 783 * 784 * @param oid The OID to check 785 * @param buffer The buffer gathering the binary OID 786 * @param bufferPos The current position in the buffer 787 * @param pos The position in the OID string 788 * @return The next OID decoding state 789 * @throws DecoderException If the OID is invalid 790 */ 791 private static OidFSAState processStateL( String oid, byte[] buffer, int bufferPos, int pos ) throws DecoderException 792 { 793 char c = oid.charAt( pos ); 794 795 switch ( c ) 796 { 797 case '.' : 798 return OidFSAState.STATE_K; 799 800 case '0' : 801 case '1' : 802 case '2' : 803 case '3' : 804 case '4' : 805 case '5' : 806 case '6' : 807 case '7' : 808 case '8' : 809 case '9' : 810 // Store the new digit at the right position in the buffer 811 buffer[bufferPos] = ( byte ) ( c - '0' ); 812 813 return OidFSAState.STATE_L; 814 815 default : 816 // Expecting a digit here 817 throw new DecoderException( I18n.err( I18n.ERR_00003_INVALID_OID, "a digit or a dot is expected" ) ); 818 } 819 } 820 821 822 /** 823 * Process state J 824 * <pre> 825 * (M) --['.']--> (K) 826 * </pre> 827 * 828 * @param oid The OID to check 829 * @param pos The position in the OID string 830 * @return The next OID decoding state 831 * @throws DecoderException If the OID is invalid 832 */ 833 private static OidFSAState processStateM( String oid, int pos ) throws DecoderException 834 { 835 char c = oid.charAt( pos ); 836 837 if ( c == '.' ) 838 { 839 return OidFSAState.STATE_K; 840 } 841 else 842 { 843 // Expecting a '.' here 844 throw new DecoderException( I18n.err( I18n.ERR_00003_INVALID_OID, "a '.' is expected" ) ); 845 } 846 } 847 848 849 /** 850 * Convert a list of digits to a list of 7 bits bytes. We must start by the end, and we don't 851 * know how many bytes we will need, except when we will be done with the conversion. 852 * 853 * @param oid The OID to convert 854 * @param buffer The buffer gathering the binary OID 855 * @param start The starting position in the OID string 856 * @param nbDigits Teh number of digits the OID has 857 * @param posBuffer The position in the buffer 858 * @param isJointIsoItuT A flag set if we know the OID is a JointIsoItuT OID 859 * @return The number of bytes required to store the OID in a PDU 860 */ 861 private static int convert( String oid, byte[] buffer, int start, int nbDigits, int posBuffer, boolean isJointIsoItuT ) 862 { 863 if ( nbDigits < 3 ) 864 { 865 // Speedup when we have a number in [0..99] : it's guaranteed to be hold 866 // by a single byte. 867 if ( isJointIsoItuT ) 868 { 869 // Another special case : this is an OID that starts with '2.' 870 buffer[0] = ( byte ) ( 80 + ( oid.charAt( 2 ) - '0' ) * 10 + ( oid.charAt( 3 ) - '0' ) ); 871 872 if ( buffer[0] < 0 ) 873 { 874 // Here, we need 2 bytes 875 buffer[1] = ( byte ) ( buffer[0] & 0x007F ); 876 buffer[0] = ( byte ) 0x81; 877 878 return 2; 879 } 880 else 881 { 882 return 1; 883 } 884 } 885 else 886 { 887 if ( nbDigits == 1 ) 888 { 889 buffer[posBuffer] = ( byte ) ( oid.charAt( start ) - '0' ); 890 } 891 else 892 { 893 buffer[posBuffer] = ( byte ) ( ( oid.charAt( start ) - '0' ) * 10 + ( oid.charAt( start + 1 ) - '0' ) ); 894 895 } 896 return 1; 897 } 898 899 } 900 else if ( nbDigits < 19 ) 901 { 902 // The value can be hold in a Long if it's up to 999999999999999999 903 // Convert the String to a long : 904 String number = oid.substring( start, start + nbDigits ); 905 906 long value = Long.parseLong( number ); 907 908 if ( isJointIsoItuT ) 909 { 910 value += 80L; 911 } 912 913 // Convert the long to a byte array 914 if ( ( value & 0xFFFFFFFFFFFFFF80L ) == 0 ) 915 { 916 // The value will be hold in one byte 917 buffer[posBuffer] = ( byte ) ( value ); 918 919 return 1; 920 } 921 922 if ( ( value & 0xFFFFFFFFFFFFC000L ) == 0 ) 923 { 924 // The value is between 0x80 and 0x3FFF : it will be hold in 2 bytes 925 buffer[posBuffer] = ( byte ) ( ( byte ) ( ( value & 0x0000000000003F80L ) >> 7 ) | 0x80 ); 926 buffer[posBuffer + 1] = ( byte ) ( value & 0x000000000000007FL ); 927 928 return 2; 929 } 930 931 if ( ( value & 0xFFFFFFFFFFE00000L ) == 0 ) 932 { 933 // The value is between 0x4000 and 0x1FFFFF : it will be hold in 3 bytes 934 buffer[posBuffer] = ( byte ) ( ( byte ) ( ( value & 0x00000000001FC000L ) >> 14 ) | 0x80 ); 935 buffer[posBuffer + 1] = ( byte ) ( ( byte ) ( ( value & 0x0000000000003F80L ) >> 7 ) | 0x80 ); 936 buffer[posBuffer + 2] = ( byte ) ( value & 0x000000000000007FL ); 937 938 return 3; 939 } 940 941 if ( ( value & 0xFFFFFFFFF0000000L ) == 0 ) 942 { 943 // The value is between 0x200000 and 0xFFFFFFF : it will be hold in 4 bytes 944 buffer[posBuffer] = ( byte ) ( ( byte ) ( ( value & 0x000000000FE00000L ) >> 21 ) | 0x80 ); 945 buffer[posBuffer + 1] = ( byte ) ( ( byte ) ( ( value & 0x00000000001FC000L ) >> 14 ) | 0x80 ); 946 buffer[posBuffer + 2] = ( byte ) ( ( byte ) ( ( value & 0x0000000000003F80L ) >> 7 ) | 0x80 ); 947 buffer[posBuffer + 3] = ( byte ) ( value & 0x000000000000007FL ); 948 949 return 4; 950 } 951 952 if ( ( value & 0xFFFFFFF800000000L ) == 0 ) 953 { 954 // The value is between 0x10000000 and 0x7FFFFFFFF : it will be hold in 5 bytes 955 buffer[posBuffer] = ( byte ) ( ( byte ) ( ( value & 0x00000007F0000000L ) >> 28 ) | 0x80 ); 956 buffer[posBuffer + 1] = ( byte ) ( ( byte ) ( ( value & 0x000000000FE00000L ) >> 21 ) | 0x80 ); 957 buffer[posBuffer + 2] = ( byte ) ( ( byte ) ( ( value & 0x00000000001FC000L ) >> 14 ) | 0x80 ); 958 buffer[posBuffer + 3] = ( byte ) ( ( byte ) ( ( value & 0x0000000000003F80L ) >> 7 ) | 0x80 ); 959 buffer[posBuffer + 4] = ( byte ) ( value & 0x000000000000007FL ); 960 961 return 5; 962 } 963 964 if ( ( value & 0xFFFFFC0000000000L ) == 0 ) 965 { 966 // The value is between 0x800000000 and 0x3FFFFFFFFFF : it will be hold in 6 bytes 967 buffer[posBuffer] = ( byte ) ( ( byte ) ( ( value & 0x000003F800000000L ) >> 35 ) | 0x80 ); 968 buffer[posBuffer + 1] = ( byte ) ( ( byte ) ( ( value & 0x00000007F0000000L ) >> 28 ) | 0x80 ); 969 buffer[posBuffer + 2] = ( byte ) ( ( byte ) ( ( value & 0x000000000FE00000L ) >> 21 ) | 0x80 ); 970 buffer[posBuffer + 3] = ( byte ) ( ( byte ) ( ( value & 0x00000000001FC000L ) >> 14 ) | 0x80 ); 971 buffer[posBuffer + 4] = ( byte ) ( ( byte ) ( ( value & 0x0000000000003F80L ) >> 7 ) | 0x80 ); 972 buffer[posBuffer + 5] = ( byte ) ( value & 0x000000000000007FL ); 973 974 return 6; 975 } 976 977 if ( ( value & 0xFFFE000000000000L ) == 0 ) 978 { 979 // The value is between 0x40000000000 and 0x1FFFFFFFFFFFF : it will be hold in 7 bytes 980 buffer[posBuffer] = ( byte ) ( ( byte ) ( ( value & 0x0001FC0000000000L ) >> 42 ) | 0x80 ); 981 buffer[posBuffer + 1] = ( byte ) ( ( byte ) ( ( value & 0x000003F800000000L ) >> 35 ) | 0x80 ); 982 buffer[posBuffer + 2] = ( byte ) ( ( byte ) ( ( value & 0x00000007F0000000L ) >> 28 ) | 0x80 ); 983 buffer[posBuffer + 3] = ( byte ) ( ( byte ) ( ( value & 0x000000000FE00000L ) >> 21 ) | 0x80 ); 984 buffer[posBuffer + 4] = ( byte ) ( ( byte ) ( ( value & 0x00000000001FC000L ) >> 14 ) | 0x80 ); 985 buffer[posBuffer + 5] = ( byte ) ( ( byte ) ( ( value & 0x0000000000003F80L ) >> 7 ) | 0x80 ); 986 buffer[posBuffer + 6] = ( byte ) ( value & 0x000000000000007FL ); 987 988 return 7; 989 } 990 991 if ( ( value & 0xFF00000000000000L ) == 0 ) 992 { 993 // The value is between 0x2000000000000 and 0xFF000000000000 : it will be hold in 8 bytes 994 buffer[posBuffer] = ( byte ) ( ( byte ) ( ( value & 0x00FE000000000000L ) >> 49 ) | 0x80 ); 995 buffer[posBuffer + 1] = ( byte ) ( ( byte ) ( ( value & 0x0001FC0000000000L ) >> 42 ) | 0x80 ); 996 buffer[posBuffer + 2] = ( byte ) ( ( byte ) ( ( value & 0x000003F800000000L ) >> 35 ) | 0x80 ); 997 buffer[posBuffer + 3] = ( byte ) ( ( byte ) ( ( value & 0x00000007F0000000L ) >> 28 ) | 0x80 ); 998 buffer[posBuffer + 4] = ( byte ) ( ( byte ) ( ( value & 0x000000000FE00000L ) >> 21 ) | 0x80 ); 999 buffer[posBuffer + 5] = ( byte ) ( ( byte ) ( ( value & 0x00000000001FC000L ) >> 14 ) | 0x80 ); 1000 buffer[posBuffer + 6] = ( byte ) ( ( byte ) ( ( value & 0x0000000000003F80L ) >> 7 ) | 0x80 ); 1001 buffer[posBuffer + 7] = ( byte ) ( value & 0x000000000000007FL ); 1002 1003 return 8; 1004 } 1005 else 1006 { 1007 // The value is between 0x100000000000000 and 0x7F00000000000000 : it will be hold in 9 bytes 1008 buffer[posBuffer] = ( byte ) ( ( byte ) ( ( value & 0x7F00000000000000L ) >> 56 ) | 0x80 ); 1009 buffer[posBuffer + 1] = ( byte ) ( ( byte ) ( ( value & 0x00FE000000000000L ) >> 49 ) | 0x80 ); 1010 buffer[posBuffer + 2] = ( byte ) ( ( byte ) ( ( value & 0x0001FC0000000000L ) >> 42 ) | 0x80 ); 1011 buffer[posBuffer + 3] = ( byte ) ( ( byte ) ( ( value & 0x000003F800000000L ) >> 35 ) | 0x80 ); 1012 buffer[posBuffer + 4] = ( byte ) ( ( byte ) ( ( value & 0x00000007F0000000L ) >> 28 ) | 0x80 ); 1013 buffer[posBuffer + 5] = ( byte ) ( ( byte ) ( ( value & 0x000000000FE00000L ) >> 21 ) | 0x80 ); 1014 buffer[posBuffer + 6] = ( byte ) ( ( byte ) ( ( value & 0x00000000001FC000L ) >> 14 ) | 0x80 ); 1015 buffer[posBuffer + 7] = ( byte ) ( ( byte ) ( ( value & 0x0000000000003F80L ) >> 7 ) | 0x80 ); 1016 buffer[posBuffer + 8] = ( byte ) ( value & 0x000000000000007FL ); 1017 1018 return 9; 1019 } 1020 } 1021 else 1022 { 1023 // The value is bigger than 9999999999999999999, we need to use a BigInteger 1024 // First, get the number of bytes we need to store the value in base 16 1025 String number = oid.substring( start, start + nbDigits ); 1026 BigInteger bigInteger = new BigInteger( number ); 1027 1028 if ( isJointIsoItuT ) 1029 { 1030 bigInteger = bigInteger.add( JOINT_ISO_ITU_T ); 1031 posBuffer = 0; 1032 } 1033 1034 byte[] bytes = bigInteger.toByteArray(); 1035 1036 // Now, convert this value to the ASN.1 OID format : we store the value 1037 // as 7 bits bytes 1038 int nbNeededBytes = ( bytes.length * 8 ) / 7; 1039 1040 switch ( ( bytes.length - 1 ) % 7 ) 1041 { 1042 case 0 : 1043 if ( ( bytes[0] & 0x0080 ) != 0 ) 1044 { 1045 nbNeededBytes++; 1046 } 1047 1048 break; 1049 1050 case 1 : 1051 if ( ( bytes[0] & 0x00C0 ) != 0 ) 1052 { 1053 nbNeededBytes++; 1054 } 1055 1056 break; 1057 1058 case 2 : 1059 if ( ( bytes[0] & 0x00E0 ) != 0 ) 1060 { 1061 nbNeededBytes++; 1062 } 1063 1064 break; 1065 1066 case 3 : 1067 if ( ( bytes[0] & 0x00F0 ) != 0 ) 1068 { 1069 nbNeededBytes++; 1070 } 1071 1072 break; 1073 1074 case 4 : 1075 if ( ( bytes[0] & 0x00F8 ) != 0 ) 1076 { 1077 nbNeededBytes++; 1078 } 1079 1080 break; 1081 1082 case 5 : 1083 if ( ( bytes[0] & 0x00FC ) != 0 ) 1084 { 1085 nbNeededBytes++; 1086 } 1087 1088 break; 1089 1090 case 6 : 1091 if ( ( bytes[0] & 0x00FE ) != 0 ) 1092 { 1093 nbNeededBytes++; 1094 } 1095 1096 break; 1097 1098 default : 1099 // Exist to please checkstyle... 1100 break; 1101 } 1102 1103 byte[] converted = new byte[nbNeededBytes]; 1104 1105 int posConverted = nbNeededBytes - 1; 1106 int posBytes = bytes.length - 1; 1107 int counter = 0; 1108 byte reminder = 0; 1109 1110 while ( posBytes >= 0 ) 1111 { 1112 byte newByte = ( byte ) ( ( bytes[posBytes] & 0x00FF ) << counter ); 1113 converted[posConverted] = ( byte ) ( reminder | newByte | 0x0080 ); 1114 reminder = ( byte ) ( ( bytes[posBytes] & 0x00FF ) >> ( 7 - counter ) ); 1115 counter = ( counter + 1 ) % 8; 1116 posConverted--; 1117 1118 if ( counter != 0 ) 1119 { 1120 posBytes--; 1121 } 1122 else 1123 { 1124 reminder = 0; 1125 } 1126 } 1127 1128 converted[nbNeededBytes - 1] &= 0x7F; 1129 1130 // Copy the converted bytes in the buffer 1131 System.arraycopy( converted, 0, buffer, posBuffer, nbNeededBytes ); 1132 1133 return nbNeededBytes; 1134 } 1135 } 1136 1137 1138 /** 1139 * Returns an OID object representing <code>oidString</code>. 1140 * 1141 * @param oidString The string representation of the OID 1142 * @return A new Oid 1143 * @throws DecoderException When the OID is not valid 1144 */ 1145 public static Oid fromString( String oidString ) throws DecoderException 1146 { 1147 if ( ( oidString == null ) || oidString.isEmpty() ) 1148 { 1149 throw new DecoderException( I18n.err( I18n.ERR_00003_INVALID_OID, "empty" ) ); 1150 } 1151 1152 // Create a buffer that is wide enough to contain all the values 1153 byte[] buffer = new byte[oidString.length()]; 1154 1155 OidFSAState state = OidFSAState.START; 1156 1157 // A counter of chars used for an arc. In 1.2.45345, this counter will be 5 for the '45345' arc. 1158 int arcNbChars = 0; 1159 1160 // The position in the buffer where we accumulate the result. 1161 int bufPos = 0; 1162 1163 // The position in the OID string where we started to read an arc 1164 int startArc = 0; 1165 1166 // The number of bytes in the resulting OID byte[] 1167 int nbBytes; 1168 1169 for ( int i = 0; i < oidString.length(); i++ ) 1170 { 1171 switch ( state ) 1172 { 1173 case START : 1174 // (Start) --['0'..'1']--> (A) 1175 // (start) --['2']--> (F) 1176 state = processStateStart( oidString, buffer, i ); 1177 break; 1178 1179 case STATE_A : 1180 // (A) --['.']--> (B) 1181 state = processStateA( oidString, i ); 1182 1183 1184 break; 1185 1186 case STATE_B : 1187 // (B) --['0']--> (D) 1188 // (B) --['1'..'3']--> (C) 1189 // (B) --['4'..'9']--> (E) 1190 state = processStateB( oidString, buffer, i ); 1191 1192 break; 1193 1194 case STATE_C : 1195 // (C) --['.']--> (K) 1196 // (C) --['0'..'9']--> (E) 1197 state = processStateC( oidString, buffer, i ); 1198 1199 // the next arc will be store at position 1 in the buffer 1200 bufPos = 1; 1201 1202 break; 1203 1204 case STATE_D : 1205 // (D) --['.']--> (K) 1206 // Fallthrough 1207 1208 case STATE_E : 1209 // (E) --['.']--> (K) 1210 state = processStateDE( oidString, buffer, i ); 1211 1212 // the next arc will be store at position 1 in teh buffer 1213 bufPos = 1; 1214 1215 break; 1216 1217 case STATE_F : 1218 // (F) --['.']--> (G) 1219 state = processStateF( oidString, i ); 1220 1221 break; 1222 1223 case STATE_G : 1224 // (G) --['0']--> (I) 1225 // (G) --['1'..'9']--> (H) 1226 state = processStateG( oidString, buffer, i ); 1227 arcNbChars = 1; 1228 startArc = i; 1229 1230 break; 1231 1232 case STATE_H : 1233 // (H) --['.']--> (K) 1234 // (H) --['0'..'9']--> (J) 1235 state = processStateH( oidString, buffer, i ); 1236 1237 if ( state == OidFSAState.STATE_J ) 1238 { 1239 // We have already two digits 1240 arcNbChars = 2; 1241 bufPos = 0; 1242 } 1243 1244 break; 1245 1246 case STATE_I : 1247 // (I) --['.']--> (K) 1248 state = processStateI( oidString, buffer, i ); 1249 1250 // Set the arc position to buffer[1], we haven't yet accumulated digits. 1251 bufPos = 1; 1252 1253 break; 1254 1255 case STATE_J : 1256 // (J) --['.']--> (K) 1257 // (J) --['0'..'9']--> (J) 1258 state = processStateJ( oidString, buffer, arcNbChars + bufPos, i ); 1259 1260 if ( state == OidFSAState.STATE_J ) 1261 { 1262 // We can increment the number of digit for this arc 1263 arcNbChars++; 1264 } 1265 else 1266 { 1267 // We are done with the first arc : convert it 1268 bufPos += convert( oidString, buffer, bufPos, arcNbChars, 0, true ); 1269 } 1270 1271 break; 1272 1273 case STATE_K : 1274 startArc = i; 1275 state = processStateK( oidString, buffer, bufPos, i ); 1276 1277 if ( state == OidFSAState.STATE_M ) 1278 { 1279 bufPos++; 1280 } 1281 else 1282 { 1283 arcNbChars = 1; 1284 } 1285 1286 break; 1287 1288 case STATE_L : 1289 state = processStateL( oidString, buffer, arcNbChars + bufPos, i ); 1290 1291 if ( state == OidFSAState.STATE_L ) 1292 { 1293 arcNbChars++; 1294 break; 1295 } 1296 else 1297 { 1298 // We are done with the arc : convert it 1299 bufPos += convert( oidString, buffer, startArc, arcNbChars, bufPos, false ); 1300 } 1301 1302 break; 1303 1304 case STATE_M : 1305 state = processStateM( oidString, i ); 1306 break; 1307 1308 default : 1309 // Exist to please checkstyle... 1310 break; 1311 } 1312 } 1313 1314 // End of the string : check that we are in a correct state for a completion 1315 // The only valid exit states are : 1316 // (C) --[]--> (End) 1317 // (D) --[]--> (End) 1318 // (E) --[]--> (End) 1319 // (H) --[]--> (End) 1320 // (I) --[]--> (End) 1321 // (J) --[]--> (End) 1322 // (L) --[]--> (End) 1323 // (M) --[]--> (End) 1324 switch ( state ) 1325 { 1326 case STATE_C : 1327 // (C) --[]--> (End) 1328 // fallthrough 1329 1330 case STATE_D : 1331 // (D) --[]--> (End) 1332 // fallthrough 1333 1334 case STATE_E : 1335 // (E) --[]--> (End) 1336 // fallthrough 1337 1338 case STATE_H : 1339 // (H) --[]--> (End) 1340 // fallthrough 1341 1342 case STATE_I : 1343 // (I) --[]--> (End) 1344 byte[] bytes = new byte[1]; 1345 bytes[0] = ( byte ) ( buffer[0] | buffer[1] ); 1346 1347 return new Oid( oidString, bytes ); 1348 1349 case STATE_J : 1350 // (J) --[]--> (End) 1351 nbBytes = convert( oidString, buffer, 2, arcNbChars, 0, true ); 1352 bytes = new byte[nbBytes]; 1353 System.arraycopy( buffer, 0, bytes, 0, nbBytes ); 1354 1355 return new Oid( oidString, bytes ); 1356 1357 case STATE_L : 1358 bufPos += convert( oidString, buffer, startArc, arcNbChars, bufPos, false ); 1359 bytes = new byte[bufPos]; 1360 System.arraycopy( buffer, 0, bytes, 0, bufPos ); 1361 1362 return new Oid( oidString, bytes ); 1363 1364 case STATE_M : 1365 bytes = new byte[bufPos]; 1366 System.arraycopy( buffer, 0, bytes, 0, bufPos ); 1367 1368 return new Oid( oidString, bytes ); 1369 1370 default : 1371 // This should never happen... 1372 throw new DecoderException( I18n.err( I18n.ERR_00003_INVALID_OID, "Wrong OID" ) ); 1373 } 1374 } 1375 1376 1377 /** 1378 * Returns the length of the encoded <code>byte[]</code> representation. 1379 * 1380 * @return The length of the byte[] 1381 */ 1382 public int getEncodedLength() 1383 { 1384 return oidBytes.length; 1385 } 1386 1387 1388 /** 1389 * {@inheritDoc} 1390 */ 1391 @Override 1392 public int hashCode() 1393 { 1394 return oidString.hashCode(); 1395 } 1396 1397 1398 /** 1399 * Returns true if <code>oidString</code> is a valid string representation 1400 * of an OID. This method simply calls {@link #fromString(String)} and 1401 * returns true if no exception was thrown. As such, it should not be used 1402 * in an attempt to check if a string is a valid OID before calling 1403 * {@link #fromString(String)}. 1404 * 1405 * @param oidString The string to test 1406 * @return True, if <code>oidString</code> is valid 1407 */ 1408 public static boolean isOid( String oidString ) 1409 { 1410 try 1411 { 1412 Oid.fromString( oidString ); 1413 1414 return true; 1415 } 1416 catch ( DecoderException e ) 1417 { 1418 return false; 1419 } 1420 } 1421 1422 1423 /** 1424 * Returns the <code>byte[]</code> representation of the OID. The 1425 * <code>byte[]</code> that is returned is <i>copied</i> from the internal 1426 * value so as to preserve the immutability of an OID object. If the 1427 * output of a call to this method is intended to be written to a stream, 1428 * the {@link #writeBytesTo(OutputStream)} should be used instead as it will 1429 * avoid creating this copy. 1430 * 1431 * @return The encoded <code>byte[]</code> representation of the OID. 1432 */ 1433 public byte[] toBytes() 1434 { 1435 return Arrays.copyOf( oidBytes, oidBytes.length ); 1436 } 1437 1438 1439 /** 1440 * Returns the string representation of the OID. 1441 * 1442 * @return The string representation of the OID 1443 */ 1444 @Override 1445 public String toString() 1446 { 1447 return oidString; 1448 } 1449 1450 1451 /** 1452 * Writes the bytes respresenting this OID to the provided buffer. This 1453 * should be used in preference to the {@link #toBytes()} method in order 1454 * to prevent the creation of copies of the actual <code>byte[]</code>. 1455 * 1456 * @param buffer The buffer to write the bytes into 1457 */ 1458 public void writeBytesTo( ByteBuffer buffer ) 1459 { 1460 buffer.put( oidBytes ); 1461 } 1462 1463 1464 /** 1465 * Writes the bytes respresenting this OID to the provided stream. This 1466 * should be used in preference to the {@link #toBytes()} method in order 1467 * to prevent the creation of copies of the actual <code>byte[]</code>. 1468 * 1469 * @param outputStream The stream to write the bytes to 1470 * @throws IOException When we can't write the OID into a Stream 1471 */ 1472 public void writeBytesTo( OutputStream outputStream ) throws IOException 1473 { 1474 outputStream.write( oidBytes ); 1475 } 1476}