View Javadoc
1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    * 
10   *    https://www.apache.org/licenses/LICENSE-2.0
11   * 
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License.
18   * 
19   */
20  package org.apache.directory.api.asn1.util;
21  
22  
23  import java.io.IOException;
24  import java.io.OutputStream;
25  import java.math.BigInteger;
26  import java.nio.ByteBuffer;
27  import java.util.Arrays;
28  
29  import org.apache.directory.api.asn1.DecoderException;
30  import org.apache.directory.api.i18n.I18n;
31  
32  
33  /**
34   * An immutable representation of an object identifier that provides conversion 
35   * between their <code>String</code>, and encoded <code>byte[]</code> 
36   * representations.
37   * 
38   * <p> The encoding of OID values is performed according to 
39   * <a href='http://www.itu.int/rec/T-REC-X.690/en'>itu X.690</a> section 8.19.
40   * Specifically:</p>
41   * 
42   * <p><b>8.19.2</b> The contents octets shall be an (ordered) list of encodings
43   * of subidentifiers (see 8.19.3 and 8.19.4) concatenated together. Each 
44   * subidentifier is represented as a series of (one or more) octets. Bit 8 of 
45   * each octet indicates whether it is the last in the series: bit 8 of the last 
46   * octet is zero; bit 8 of each preceding octet is one. Bits 7 to 1 of the 
47   * octets in the series collectively encode the subidentifier. Conceptually, 
48   * these groups of bits are concatenated to form an unsigned binary number whose 
49   * most significant bit is bit 7 of the first octet and whose least significant 
50   * bit is bit 1 of the last octet. The subidentifier shall be encoded in the 
51   * fewest possible octets, that is, the leading octet of the subidentifier shall 
52   * not have the value 0x80. </p>
53   * 
54   * <p><b>8.19.3</b> The number of subidentifiers (N) shall be one less than the 
55   * number of object identifier components in the object identifier value being 
56   * encoded.</p>
57   * 
58   * <p><b>8.19.4</b> The numerical value of the first subidentifier is derived 
59   * from the values of the first two object identifier components in the object 
60   * identifier value being encoded, using the formula:
61   * <br><code>(X*40) + Y</code><br> 
62   * where X is the value of the first object identifier component and Y is the 
63   * value of the second object identifier component. <i>NOTE – This packing of 
64   * the first two object identifier components recognizes that only three values 
65   * are allocated from the root node, and at most 39 subsequent values from nodes 
66   * reached by X = 0 and X = 1.</i></p>
67   * 
68   * <p>For example, the OID "2.12.3456.7" would be turned into a list of 3 values:
69   * <code>[((2*40)+12), 3456, 7]</code>. The first of which, 
70   * <code>92</code>, would be encoded as the bytes <code>0x5C</code>, the second 
71   * would be <code>[0x9B, 0x00]</code>, and the third as <code>0x07</code>
72   * giving the final encoding <code>[0x5C, 0x9B, 0x00, 0x07]</code>.</p>
73   * 
74   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
75   */
76  public final class Oid
77  {
78      /** A byte[] representation of an OID */
79      private byte[] oidBytes;
80      
81      /** The OID as a String */
82      private String oidString;
83      
84      private static final BigInteger JOINT_ISO_ITU_T = BigInteger.valueOf( 80 );
85      
86      /**
87       * The OID FSA states. We have the following Finite State Automaton :
88       * 
89       * <pre>
90       * (Start) --['0','1']--&gt; (A)
91       * (start) --['2']--&gt; (F)
92       * 
93       * (A) --['.']--&gt; (B)
94       * 
95       * (B) --['0']--&gt; (D)
96       * (B) --['1'..'3']--&gt; (C)
97       * (B) --['4'..'9']--&gt; (E)
98       * 
99       * (C) --[]--&gt; (End)
100      * (C) --['.']--&gt; (K)
101      * (C) --['0'..'9']--&gt; (E)
102      * 
103      * (D) --[]--&gt; (End)
104      * (D) --['.']--&gt; (K)
105      * 
106      * (E) --[]--&gt; (End)
107      * (E) --['.']--&gt; (K)
108      * 
109      * (F) --['.']--&gt; (G)
110      * 
111      * (G) --['0']--&gt; (I)
112      * (G) --['1'..'9']--&gt; (H)
113      *
114      * (H) --[]--&gt; (End)
115      * (H) --['.']--&gt; (K)
116      * (H) --['0'..'9']--&gt; (J)
117      * 
118      * (I) --[]--&gt; (End)
119      * (I) --['.']--&gt; (K)
120      *
121      * (J) --[]--&gt; (End)
122      * (J) --['.']--&gt; (K)
123      * (J) --['0'..'9']--&gt; (J)
124      * 
125      * (K) --['0']--&gt; (M) 
126      * (K) --['1'..'9']--&gt; (L)
127      * 
128      * (L) --[]--&gt; (End)
129      * (L) --['.']--&gt; (K)
130      * (L) --['0'..'9']--&gt; (L)
131      * 
132      * (M) --[]--&gt; (End)
133      * (M) --['.']--&gt; (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']--&gt; (A)
372      * (start) --['2']--&gt; (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) --['.']--&gt; (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']--&gt; (D)
429      * (B) --['1'..'3']--&gt; (C)
430      * (B) --['4'..'9']--&gt; (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) --['.']--&gt; (K)
476      * (C) --['0'..'9']--&gt; (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) --['.']--&gt; (K)
521      * (E) --['.']--&gt; (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) --['.']--&gt; (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']--&gt; (I)
575      * (G) --['1'..'9']--&gt; (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) --['.']--&gt; (K)
618      * (H) --['0'..'9']--&gt; (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) --['.']--&gt; (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) --['.']--&gt; (K)
694      * (J) --['0'..'9']--&gt; (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']--&gt; (M)
738      * (K) --['1'..'9']--&gt; (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) --['.']--&gt; (K)
781      * (L) --['0'..'9']--&gt; (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) --['.']--&gt; (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 }